595 prev next chunks index CyanogenMod/android_packages_apps_Trebuchet_cd76f89f127b3a817f486ec14d76de9d79ecd5bb_src/com/android/launcher3/LauncherModel.java {strict: [[b], [b], [j], [j]], subset: [[b], [b], [j], [j]]}
line based (standard git) jfstmerge spork
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.app.SearchManager;                                                                        
  20 import android.appwidget.AppWidgetManager;                                                               
  21 import android.appwidget.AppWidgetProviderInfo;                                                          
  22 import android.content.*;                                                                                
  23 import android.content.Intent.ShortcutIconResource;                                                      
  24 import android.content.pm.ActivityInfo;                                                                  
  25 import android.content.pm.PackageInfo;                                                                   
  26 import android.content.pm.PackageManager;                                                                
  27 import android.content.pm.PackageManager.NameNotFoundException;                                          
  28 import android.content.pm.ResolveInfo;                                                                   
  29 import android.content.res.Configuration;                                                                
  30 import android.content.res.Resources;                                                                    
  31 import android.database.Cursor;                                                                          
  32 import android.graphics.Bitmap;                                                                          
  33 import android.graphics.BitmapFactory;                                                                   
  34 import android.net.Uri;                                                                                  
  35 import android.os.Environment;                                                                           
  36 import android.os.Handler;                                                                               
  37 import android.os.HandlerThread;                                                                         
  38 import android.os.Parcelable;                                                                            
  39 import android.os.Process;                                                                               
  40 import android.os.RemoteException;                                                                       
  41 import android.os.SystemClock;                                                                           
  42 import android.provider.BaseColumns;                                                                     
  43 import android.text.TextUtils;                                                                           
  44 import android.util.Log;                                                                                 
  45 import android.util.Pair;                                                                                
  46                                                                                                          
  47 import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;                            
  48                                                                                                          
  49 import java.lang.ref.WeakReference;                                                                      
  50 import java.net.URISyntaxException;                                                                      
  51 import java.text.Collator;                                                                               
  52 import java.util.ArrayList;                                                                              
  53 import java.util.Arrays;                                                                                 
  54 import java.util.Collection;                                                                             
  55 import java.util.Collections;                                                                            
  56 import java.util.Comparator;                                                                             
  57 import java.util.HashMap;                                                                                
  58 import java.util.HashSet;                                                                                
  59 import java.util.Iterator;                                                                               
  60 import java.util.List;                                                                                   
  61 import java.util.Set;                                                                                    
  62 import java.util.TreeMap;                                                                                
  63 import java.util.concurrent.atomic.AtomicBoolean;                                                        
  64                                                                                                          
  65 /**                                                                                                      
  66  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  67  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  68  * for the Launcher.                                                                                     
  69  */                                                                                                      
  70 public class LauncherModel extends BroadcastReceiver {                                                   
  71     static final boolean DEBUG_LOADERS = false;                                                          
  72     static final String TAG = "Launcher.Model";                                                          
  73                                                                                                          
  74     // true = use a "More Apps" folder for non-workspace apps on upgrade                                 
  75     // false = strew non-workspace apps across the workspace on upgrade                                  
  76     public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;                                    
  77                                                                                                          
  78     public static final int LOADER_FLAG_NONE = 0;                                                        
  79     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  80     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  81                                                                                                          
  82     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
  83     private static final long INVALID_SCREEN_ID = -1L;                                                   
  84                                                                                                          
  85     private final boolean mAppsCanBeOnRemoveableStorage;                                                 
  86     private final boolean mOldContentProviderExists;                                                     
  87                                                                                                          
  88     private final LauncherAppState mApp;                                                                 
  89     private final Object mLock = new Object();                                                           
  90     private DeferredHandler mHandler = new DeferredHandler();                                            
  91     private LoaderTask mLoaderTask;                                                                      
  92     private boolean mIsLoaderTaskRunning;                                                                
  93     private volatile boolean mFlushingWorkerThread;                                                      
  94                                                                                                          
  95     // Specific runnable types that are run on the main thread deferred handler, this allows us to       
  96     // clear all queued binding runnables when the Launcher activity is destroyed.                       
  97     private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                            
  98     private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                           
  99                                                                                                          
 100                                                                                                          
 101     private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");             
 102     static {                                                                                             
 103         sWorkerThread.start();                                                                           
 104     }                                                                                                    
 105     private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                       
 106                                                                                                          
 107     // We start off with everything not loaded.  After that, we assume that                              
 108     // our monitoring of the package manager provides all updates and we never                           
 109     // need to do a requery.  These are only ever touched from the loader thread.                        
 110     private boolean mWorkspaceLoaded;                                                                    
 111     private boolean mAllAppsLoaded;                                                                      
 112                                                                                                          
 113     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 114     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 115     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 116     // a normal load, we also clear this set of Runnables.                                               
 117     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 118                                                                                                          
 119     private WeakReference<Callbacks> mCallbacks;                                                         
 120                                                                                                          
 121     // < only access in worker thread >                                                                  
 122     AllAppsList mBgAllAppsList;                                                                          
 123                                                                                                          
 124     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 125     // other locks, this one can generally be held long-term because we never expect any of these        
 126     // static data structures to be referenced outside of the worker thread except on the first          
 127     // load after configuration change.                                                                  
 128     static final Object sBgLock = new Object();                                                          
 129                                                                                                          
 130     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 131     // LauncherModel to their ids                                                                        
 132     static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                  
 133                                                                                                          
 134     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 135     //       created by LauncherModel that are directly on the home screen (however, no widgets or       
 136     //       shortcuts within folders).                                                                  
 137     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 138                                                                                                          
 139     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 140     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 141         new ArrayList<LauncherAppWidgetInfo>();                                                          
 142                                                                                                          
 143     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 144     static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                 
 145                                                                                                          
 146     // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database      
 147     static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                 
 148                                                                                                          
 149     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 150     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 151                                                                                                          
 152     // </ only access in worker thread >                                                                 
 153                                                                                                          
 154     private IconCache mIconCache;                                                                        
 155     private Bitmap mDefaultIcon;                                                                         
 156                                                                                                          
 157     protected int mPreviousConfigMcc;                                                                    
 158                                                                                                          
 159     public interface Callbacks {                                                                         
 160         public boolean setLoadOnResume();                                                                
 161         public int getCurrentWorkspaceScreen();                                                          
 162         public void startBinding();                                                                      
 163         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                         
 164                               boolean forceAnimateIcons);                                                
 165         public void bindScreens(ArrayList<Long> orderedScreenIds);                                       
 166         public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                    
 167         public void bindFolders(HashMap<Long,FolderInfo> folders);                                       
 168         public void finishBindingItems(boolean upgradePath);                                             
 169         public void bindAppWidget(LauncherAppWidgetInfo info);                                           
 170         public void bindAllApplications(ArrayList<AppInfo> apps);                                        
 171         public void bindAppsAdded(ArrayList<Long> newScreens,                                            
 172                                   ArrayList<ItemInfo> addNotAnimated,                                    
 173                                   ArrayList<ItemInfo> addAnimated,                                       
 174                                   ArrayList<AppInfo> addedApps);                                         
 175         public void bindAppsUpdated(ArrayList<AppInfo> apps);                                            
 176         public void bindComponentsRemoved(ArrayList<String> packageNames,                                
 177                         ArrayList<AppInfo> appInfos);                                                    
 178         public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                          
 179         public void bindSearchablesChanged();                                                            
 180         public boolean isAllAppsButtonRank(int rank);                                                    
 181         public void onPageBoundSynchronously(int page);                                                  
 182         public void dumpLogsToLocalData();                                                               
 183     }                                                                                                    
 184                                                                                                          
 185     public interface ItemInfoFilter {                                                                    
 186         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                     
 187     }                                                                                                    
 188                                                                                                          
 189     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 190         Context context = app.getContext();                                                              
 191         ContentResolver contentResolver = context.getContentResolver();                                  
 192                                                                                                          
 193         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 194         mOldContentProviderExists = (contentResolver.acquireContentProviderClient(                       
 195                 LauncherSettings.Favorites.OLD_CONTENT_URI) != null);                                    
 196         mApp = app;                                                                                      
 197         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 198         mIconCache = iconCache;                                                                          
 199                                                                                                          
 200         final Resources res = context.getResources();                                                    
 201         Configuration config = res.getConfiguration();                                                   
 202         mPreviousConfigMcc = config.mcc;                                                                 
 203     }                                                                                                    
 204                                                                                                          
 205     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 206      * posted on the main thread handler. */                                                             
 207     private void runOnMainThread(Runnable r) {                                                           
 208         runOnMainThread(r, 0);                                                                           
 209     }                                                                                                    
 210     private void runOnMainThread(Runnable r, int type) {                                                 
 211         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 212             // If we are on the worker thread, post onto the main handler                                
 213             mHandler.post(r);                                                                            
 214         } else {                                                                                         
 215             r.run();                                                                                     
 216         }                                                                                                
 217     }                                                                                                    
 218                                                                                                          
 219     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 220      * posted on the worker thread handler. */                                                           
 221     private static void runOnWorkerThread(Runnable r) {                                                  
 222         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 223             r.run();                                                                                     
 224         } else {                                                                                         
 225             // If we are not on the worker thread, then post to the worker handler                       
 226             sWorker.post(r);                                                                             
 227         }                                                                                                
 228     }                                                                                                    
 229                                                                                                          
 230     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 231         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 232     }                                                                                                    
 233                                                                                                          
 234     static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy,               
 235                                  long screen) {                                                          
 236         LauncherAppState app = LauncherAppState.getInstance();                                           
 237         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 238         final int xCount = (int) grid.numColumns;                                                        
 239         final int yCount = (int) grid.numRows;                                                           
 240         boolean[][] occupied = new boolean[xCount][yCount];                                              
 241                                                                                                          
 242         int cellX, cellY, spanX, spanY;                                                                  
 243         for (int i = 0; i < items.size(); ++i) {                                                         
 244             final ItemInfo item = items.get(i);                                                          
 245             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                        
 246                 if (item.screenId == screen) {                                                           
 247                     cellX = item.cellX;                                                                  
 248                     cellY = item.cellY;                                                                  
 249                     spanX = item.spanX;                                                                  
 250                     spanY = item.spanY;                                                                  
 251                     for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {                
 252                         for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {            
 253                             occupied[x][y] = true;                                                       
 254                         }                                                                                
 255                     }                                                                                    
 256                 }                                                                                        
 257             }                                                                                            
 258         }                                                                                                
 259                                                                                                          
 260         return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);                            
 261     }                                                                                                    
 262     static Pair<Long, int[]> findNextAvailableIconSpace(Context context, String name,                    
 263                                                         Intent launchIntent,                             
 264                                                         int firstScreenIndex,                            
 265                                                         ArrayList<Long> workspaceScreens) {              
 266         // Lock on the app so that we don't try and get the items while apps are being added             
 267         LauncherAppState app = LauncherAppState.getInstance();                                           
 268         LauncherModel model = app.getModel();                                                            
 269         boolean found = false;                                                                           
 270         synchronized (app) {                                                                             
 271             if (sWorkerThread.getThreadId() != Process.myTid()) {                                        
 272                 // Flush the LauncherModel worker thread, so that if we just did another                 
 273                 // processInstallShortcut, we give it time for its shortcut to get added to the          
 274                 // database (getItemsInLocalCoordinates reads the database)                              
 275                 model.flushWorkerThread();                                                               
 276             }                                                                                            
 277             final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);         
 278                                                                                                          
 279             // Try adding to the workspace screens incrementally, starting at the default or center      
 280             // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))       
 281             firstScreenIndex = Math.min(firstScreenIndex, workspaceScreens.size());                      
 282             int count = workspaceScreens.size();                                                         
 283             for (int screen = firstScreenIndex; screen < count && !found; screen++) {                    
 284                 int[] tmpCoordinates = new int[2];                                                       
 285                 if (findNextAvailableIconSpaceInScreen(items, tmpCoordinates,                            
 286                         workspaceScreens.get(screen))) {                                                 
 287                     // Update the Launcher db                                                            
 288                     return new Pair<Long, int[]>(workspaceScreens.get(screen), tmpCoordinates);          
 289                 }                                                                                        
 290             }                                                                                            
 291         }                                                                                                
 292         return null;                                                                                     
 293     }                                                                                                    
 294                                                                                                          
 295 <<<<<<< GitAnalyzerPlus_ours                                                                             
 296     public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps,      
 297                                     final ArrayList<AppInfo> allAppsApps) {                              
 298         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                     
 299         addAndBindAddedApps(context, workspaceApps, cb, allAppsApps);                                    
 300 ||||||| GitAnalyzerPlus_base                                                                             
 301     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 302         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                        
 303                                                                                                          
 304         if (allAppsApps == null) {                                                                       
 305             throw new RuntimeException("allAppsApps must not be null");                                  
 306         }                                                                                                
 307         if (allAppsApps.isEmpty()) {                                                                     
 308             return;                                                                                      
 309         }                                                                                                
 310                                                                                                          
 311         // Process the newly added applications and add them to the database first                       
 312         Runnable r = new Runnable() {                                                                    
 313             public void run() {                                                                          
 314                 runOnMainThread(new Runnable() {                                                         
 315                     public void run() {                                                                  
 316                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
 317                         if (callbacks == cb && cb != null) {                                             
 318                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 319                         }                                                                                
 320                     }                                                                                    
 321                 });                                                                                      
 322             }                                                                                            
 323         };                                                                                               
 324         runOnWorkerThread(r);                                                                            
 325     }                                                                                                    
 326                                                                                                          
 327     public void addAndBindAddedWorkspaceApps(final Context context,                                      
 328             final ArrayList<ItemInfo> workspaceApps) {                                                   
 329         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                        
 330                                                                                                          
 331         if (workspaceApps == null) {                                                                     
 332             throw new RuntimeException("workspaceApps and allAppsApps must not be null");                
 333         }                                                                                                
 334         if (workspaceApps.isEmpty()) {                                                                   
 335             return;                                                                                      
 336         }                                                                                                
 337 =======                                                                                                  
 338     public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {              
 339         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                        
 340                                                                                                          
 341         if (allAppsApps == null) {                                                                       
 342             throw new RuntimeException("allAppsApps must not be null");                                  
 343         }                                                                                                
 344         if (allAppsApps.isEmpty()) {                                                                     
 345             return;                                                                                      
 346         }                                                                                                
 347                                                                                                          
 348         final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();                           
 349         Iterator<AppInfo> iter = allAppsApps.iterator();                                                 
 350         while (iter.hasNext()) {                                                                         
 351             ItemInfo a = iter.next();                                                                    
 352             if (LauncherModel.appWasRestored(ctx, a.getIntent())) {                                      
 353                 restoredAppsFinal.add((AppInfo) a);                                                      
 354             }                                                                                            
 355         }                                                                                                
 356                                                                                                          
 357         // Process the newly added applications and add them to the database first                       
 358         Runnable r = new Runnable() {                                                                    
 359             public void run() {                                                                          
 360                 runOnMainThread(new Runnable() {                                                         
 361                     public void run() {                                                                  
 362                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
 363                         if (callbacks == cb && cb != null) {                                             
 364                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 365                             if (!restoredAppsFinal.isEmpty()) {                                          
 366                                 callbacks.bindAppsUpdated(restoredAppsFinal);                            
 367                             }                                                                            
 368                         }                                                                                
 369                     }                                                                                    
 370                 });                                                                                      
 371             }                                                                                            
 372         };                                                                                               
 373         runOnWorkerThread(r);                                                                            
 374 >>>>>>> GitAnalyzerPlus_theirs                                                                           
 375     }                                                                                                    
 376     public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps,      
 377                                 final Callbacks callbacks, final ArrayList<AppInfo> allAppsApps) {       
 378         if (workspaceApps == null || allAppsApps == null) {                                              
 379             throw new RuntimeException("workspaceApps and allAppsApps must not be null");                
 380         }                                                                                                
 381         if (workspaceApps.isEmpty() && allAppsApps.isEmpty()) {                                          
 382             return;                                                                                      
 383         }                                                                                                
 384         // Process the newly added applications and add them to the database first                       
 385         Runnable r = new Runnable() {                                                                    
 386             public void run() {                                                                          
 387                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 388                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 389                 final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();                   
 390                                                                                                          
 391                 // Get the list of workspace screens.  We need to append to this list and                
 392                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 393                 // called.                                                                               
 394                 ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                
 395                 TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                 
 396                 for (Integer i : orderedScreens.keySet()) {                                              
 397                     long screenId = orderedScreens.get(i);                                               
 398                     workspaceScreens.add(screenId);                                                      
 399                 }                                                                                        
 400                                                                                                          
 401                 synchronized(sBgLock) {                                                                  
 402                     Iterator<ItemInfo> iter = workspaceApps.iterator();                                  
 403                     while (iter.hasNext()) {                                                             
 404                         ItemInfo a = iter.next();                                                        
 405                         final String name = a.title.toString();                                          
 406                         final Intent launchIntent = a.getIntent();                                       
 407                                                                                                          
 408                         // Short-circuit this logic if the icon exists somewhere on the workspace        
 409                         if (LauncherModel.shortcutExists(context, name, launchIntent)) {                 
 410                             // Only InstallShortcutReceiver sends us shortcutInfos, ignore them          
 411                             if (a instanceof AppInfo &&                                                  
 412                                     LauncherModel.appWasRestored(context, launchIntent)) {               
 413                                 restoredAppsFinal.add((AppInfo) a);                                      
 414                             }                                                                            
 415                             continue;                                                                    
 416                         }                                                                                
 417                                                                                                          
 418                         // Add this icon to the db, creating a new page if necessary.  If there          
 419                         // is only the empty page then we just add items to the first page.              
 420                         // Otherwise, we add them to the next pages.                                     
 421                         int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;                   
 422                         Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,     
 423                                 name, launchIntent, startSearchPageIndex, workspaceScreens);             
 424                         if (coords == null) {                                                            
 425                             LauncherProvider lp = LauncherAppState.getLauncherProvider();                
 426                                                                                                          
 427                             // If we can't find a valid position, then just add a new screen.            
 428                             // This takes time so we need to re-queue the add until the new              
 429                             // page is added.  Create as many screens as necessary to satisfy            
 430                             // the startSearchPageIndex.                                                 
 431                             int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -                   
 432                                     workspaceScreens.size());                                            
 433                             while (numPagesToAdd > 0) {                                                  
 434                                 long screenId = lp.generateNewScreenId();                                
 435                                 // Save the screen id for binding in the workspace                       
 436                                 workspaceScreens.add(screenId);                                          
 437                                 addedWorkspaceScreensFinal.add(screenId);                                
 438                                 numPagesToAdd--;                                                         
 439                             }                                                                            
 440                                                                                                          
 441                             // Find the coordinate again                                                 
 442                             coords = LauncherModel.findNextAvailableIconSpace(context,                   
 443                                     name, launchIntent, startSearchPageIndex, workspaceScreens);         
 444                         }                                                                                
 445                         if (coords == null) {                                                            
 446                             throw new RuntimeException("Coordinates should not be null");                
 447                         }                                                                                
 448                                                                                                          
 449                         ShortcutInfo shortcutInfo;                                                       
 450                         if (a instanceof ShortcutInfo) {                                                 
 451                             shortcutInfo = (ShortcutInfo) a;                                             
 452                         } else if (a instanceof AppInfo) {                                               
 453                             shortcutInfo = ((AppInfo) a).makeShortcut();                                 
 454                         } else {                                                                         
 455                             throw new RuntimeException("Unexpected info type");                          
 456                         }                                                                                
 457                                                                                                          
 458                         // Add the shortcut to the db                                                    
 459                         addItemToDatabase(context, shortcutInfo,                                         
 460                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 461                                 coords.first, coords.second[0], coords.second[1], false);                
 462                         // Save the ShortcutInfo for binding in the workspace                            
 463                         addedShortcutsFinal.add(shortcutInfo);                                           
 464                     }                                                                                    
 465                 }                                                                                        
 466                                                                                                          
 467                 // Update the workspace screens                                                          
 468                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 469                                                                                                          
 470                 if (!addedShortcutsFinal.isEmpty() || !allAppsApps.isEmpty()) {                          
 471                     runOnMainThread(new Runnable() {                                                     
 472                         public void run() {                                                              
 473                             Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                 
 474                             if (callbacks == cb && cb != null) {                                         
 475                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 476                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 477                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 478                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 479                                     long lastScreenId = info.screenId;                                   
 480                                     for (ItemInfo i : addedShortcutsFinal) {                             
 481                                         if (i.screenId == lastScreenId) {                                
 482                                             addAnimated.add(i);                                          
 483                                         } else {                                                         
 484                                             addNotAnimated.add(i);                                       
 485                                         }                                                                
 486                                     }                                                                    
 487                                 }                                                                        
 488                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 489 <<<<<<< GitAnalyzerPlus_ours                                                                             
 490                                         addNotAnimated, addAnimated, allAppsApps);                       
 491 ||||||| GitAnalyzerPlus_base                                                                             
 492                                                                                                          
 493                 // Update the workspace screens                                                          
 494                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 495                                                                                                          
 496                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 497                     runOnMainThread(new Runnable() {                                                     
 498                         public void run() {                                                              
 499                             Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                 
 500                             if (callbacks == cb && cb != null) {                                         
 501                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 502                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 503                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 504                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 505                                     long lastScreenId = info.screenId;                                   
 506                                     for (ItemInfo i : addedShortcutsFinal) {                             
 507                                         if (i.screenId == lastScreenId) {                                
 508                                             addAnimated.add(i);                                          
 509                                         } else {                                                         
 510                                             addNotAnimated.add(i);                                       
 511                                         }                                                                
 512                                     }                                                                    
 513                                 }                                                                        
 514                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 515                                         addNotAnimated, addAnimated, null);                              
 516                             }                                                                            
 517                         }                                                                                
 518                     });                                                                                  
 519                 }                                                                                        
 520             }                                                                                            
 521         };                                                                                               
 522         runOnWorkerThread(r);                                                                            
 523     }                                                                                                    
 524                                                                                                          
 525     public Bitmap getFallbackIcon() {                                                                    
 526         if (mDefaultIcon == null) {                                                                      
 527             final Context context = LauncherAppState.getInstance().getContext();                         
 528             mDefaultIcon = Utilities.createIconBitmap(                                                   
 529                     mIconCache.getFullResDefaultActivityIcon(), context);                                
 530         }                                                                                                
 531         return Bitmap.createBitmap(mDefaultIcon);                                                        
 532     }                                                                                                    
 533                                                                                                          
 534     public void unbindItemInfosAndClearQueuedBindRunnables() {                                           
 535         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 536             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 537 =======                                                                                                  
 538                                         addNotAnimated, addAnimated, null);                              
 539                                 if (!restoredAppsFinal.isEmpty()) {                                      
 540                                     callbacks.bindAppsUpdated(restoredAppsFinal);                        
 541                                 }                                                                        
 542 >>>>>>> GitAnalyzerPlus_theirs                                                                           
 543                             }                                                                            
 544                         }                                                                                
 545                     });                                                                                  
 546                 }                                                                                        
 547             }                                                                                            
 548         };                                                                                               
 549         runOnWorkerThread(r);                                                                            
 550     }                                                                                                    
 551                                                                                                          
 552     public Bitmap getFallbackIcon() {                                                                    
 553         if (mDefaultIcon == null) {                                                                      
 554             final Context context = LauncherAppState.getInstance().getContext();                         
 555             mDefaultIcon = Utilities.createIconBitmap(                                                   
 556                     mIconCache.getFullResDefaultActivityIcon(), context);                                
 557         }                                                                                                
 558         return Bitmap.createBitmap(mDefaultIcon);                                                        
 559     }                                                                                                    
 560                                                                                                          
 561     public void unbindItemInfosAndClearQueuedBindRunnables() {                                           
 562         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 563             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 564                     "main thread");                                                                      
 565         }                                                                                                
 566                                                                                                          
 567         // Clear any deferred bind runnables                                                             
 568         mDeferredBindRunnables.clear();                                                                  
 569         // Remove any queued bind runnables                                                              
 570         mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                 
 571         // Unbind all the workspace items                                                                
 572         unbindWorkspaceItemsOnMainThread();                                                              
 573     }                                                                                                    
 574                                                                                                          
 575     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 576     void unbindWorkspaceItemsOnMainThread() {                                                            
 577         // Ensure that we don't use the same workspace items data structure on the main thread           
 578         // by making a copy of workspace items first.                                                    
 579         final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                         
 580         final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                             
 581         synchronized (sBgLock) {                                                                         
 582             tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                 
 583             tmpAppWidgets.addAll(sBgAppWidgets);                                                         
 584         }                                                                                                
 585         Runnable r = new Runnable() {                                                                    
 586                 @Override                                                                                
 587                 public void run() {                                                                      
 588                    for (ItemInfo item : tmpWorkspaceItems) {                                             
 589                        item.unbind();                                                                    
 590                    }                                                                                     
 591                    for (ItemInfo item : tmpAppWidgets) {                                                 
 592                        item.unbind();                                                                    
 593                    }                                                                                     
 594                 }                                                                                        
 595             };                                                                                           
 596         runOnMainThread(r);                                                                              
 597     }                                                                                                    
 598                                                                                                          
 599     /**                                                                                                  
 600      * Adds an item to the DB if it was not created previously, or move it to a new                      
 601      * <container, screen, cellX, cellY>                                                                 
 602      */                                                                                                  
 603     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 604             long screenId, int cellX, int cellY) {                                                       
 605         if (item.container == ItemInfo.NO_ID) {                                                          
 606             // From all apps                                                                             
 607             addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                  
 608         } else {                                                                                         
 609             // From somewhere else                                                                       
 610             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 611         }                                                                                                
 612     }                                                                                                    
 613                                                                                                          
 614     static void checkItemInfoLocked(                                                                     
 615             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 616         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 617         if (modelItem != null && item != modelItem) {                                                    
 618             // check all the data is consistent                                                          
 619             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 620                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 621                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 622                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 623                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 624                         modelShortcut.id == shortcut.id &&                                               
 625                         modelShortcut.itemType == shortcut.itemType &&                                   
 626                         modelShortcut.container == shortcut.container &&                                 
 627                         modelShortcut.screenId == shortcut.screenId &&                                   
 628                         modelShortcut.cellX == shortcut.cellX &&                                         
 629                         modelShortcut.cellY == shortcut.cellY &&                                         
 630                         modelShortcut.spanX == shortcut.spanX &&                                         
 631                         modelShortcut.spanY == shortcut.spanY &&                                         
 632                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 633                         (modelShortcut.dropPos != null &&                                                
 634                                 shortcut.dropPos != null &&                                              
 635                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 636                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 637                     // For all intents and purposes, this is the same object                             
 638                     return;                                                                              
 639                 }                                                                                        
 640             }                                                                                            
 641                                                                                                          
 642             // the modelItem needs to match up perfectly with item if our model is                       
 643             // to be consistent with the database-- for now, just require                                
 644             // modelItem == item or the equality check above                                             
 645             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 646                     "modelItem: " +                                                                      
 647                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 648                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 649             RuntimeException e = new RuntimeException(msg);                                              
 650             if (stackTrace != null) {                                                                    
 651                 e.setStackTrace(stackTrace);                                                             
 652             }                                                                                            
 653             throw e;                                                                                     
 654         }                                                                                                
 655     }                                                                                                    
 656                                                                                                          
 657     static void checkItemInfo(final ItemInfo item) {                                                     
 658         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 659         final long itemId = item.id;                                                                     
 660         Runnable r = new Runnable() {                                                                    
 661             public void run() {                                                                          
 662                 synchronized (sBgLock) {                                                                 
 663                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 664                 }                                                                                        
 665             }                                                                                            
 666         };                                                                                               
 667         runOnWorkerThread(r);                                                                            
 668     }                                                                                                    
 669                                                                                                          
 670     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 671             final ItemInfo item, final String callingFunction) {                                         
 672         final long itemId = item.id;                                                                     
 673         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                         
 674         final ContentResolver cr = context.getContentResolver();                                         
 675                                                                                                          
 676         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 677         Runnable r = new Runnable() {                                                                    
 678             public void run() {                                                                          
 679                 cr.update(uri, values, null, null);                                                      
 680                 updateItemArrays(item, itemId, stackTrace);                                              
 681             }                                                                                            
 682         };                                                                                               
 683         runOnWorkerThread(r);                                                                            
 684     }                                                                                                    
 685                                                                                                          
 686     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 687             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 688         final ContentResolver cr = context.getContentResolver();                                         
 689                                                                                                          
 690         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 691         Runnable r = new Runnable() {                                                                    
 692             public void run() {                                                                          
 693                 ArrayList<ContentProviderOperation> ops =                                                
 694                         new ArrayList<ContentProviderOperation>();                                       
 695                 int count = items.size();                                                                
 696                 for (int i = 0; i < count; i++) {                                                        
 697                     ItemInfo item = items.get(i);                                                        
 698                     final long itemId = item.id;                                                         
 699                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);             
 700                     ContentValues values = valuesList.get(i);                                            
 701                                                                                                          
 702                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 703                     updateItemArrays(item, itemId, stackTrace);                                          
 704                                                                                                          
 705                 }                                                                                        
 706                 try {                                                                                    
 707                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 708                 } catch (Exception e) {                                                                  
 709                     e.printStackTrace();                                                                 
 710                 }                                                                                        
 711             }                                                                                            
 712         };                                                                                               
 713         runOnWorkerThread(r);                                                                            
 714     }                                                                                                    
 715                                                                                                          
 716     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 717         // Lock on mBgLock *after* the db operation                                                      
 718         synchronized (sBgLock) {                                                                         
 719             checkItemInfoLocked(itemId, item, stackTrace);                                               
 720                                                                                                          
 721             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 722                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 723                 // Item is in a folder, make sure this folder exists                                     
 724                 if (!sBgFolders.containsKey(item.container)) {                                           
 725                     // An items container is being set to a that of an item which is not in              
 726                     // the list of Folders.                                                              
 727                     String msg = "item: " + item + " container being set to: " +                         
 728                             item.container + ", not in the list of folders";                             
 729                     Log.e(TAG, msg);                                                                     
 730                 }                                                                                        
 731             }                                                                                            
 732                                                                                                          
 733             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 734             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 735             // that are on the desktop, as appropriate                                                   
 736             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 737             if (modelItem != null &&                                                                     
 738                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 739                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 740                 switch (modelItem.itemType) {                                                            
 741                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 742                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 743                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 744                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 745                             sBgWorkspaceItems.add(modelItem);                                            
 746                         }                                                                                
 747                         break;                                                                           
 748                     default:                                                                             
 749                         break;                                                                           
 750                 }                                                                                        
 751             } else {                                                                                     
 752                 sBgWorkspaceItems.remove(modelItem);                                                     
 753             }                                                                                            
 754         }                                                                                                
 755     }                                                                                                    
 756                                                                                                          
 757     public void flushWorkerThread() {                                                                    
 758         mFlushingWorkerThread = true;                                                                    
 759         Runnable waiter = new Runnable() {                                                               
 760                 public void run() {                                                                      
 761                     synchronized (this) {                                                                
 762                         notifyAll();                                                                     
 763                         mFlushingWorkerThread = false;                                                   
 764                     }                                                                                    
 765                 }                                                                                        
 766             };                                                                                           
 767                                                                                                          
 768         synchronized(waiter) {                                                                           
 769             runOnWorkerThread(waiter);                                                                   
 770             if (mLoaderTask != null) {                                                                   
 771                 synchronized(mLoaderTask) {                                                              
 772                     mLoaderTask.notify();                                                                
 773                 }                                                                                        
 774             }                                                                                            
 775             boolean success = false;                                                                     
 776             while (!success) {                                                                           
 777                 try {                                                                                    
 778                     waiter.wait();                                                                       
 779                     success = true;                                                                      
 780                 } catch (InterruptedException e) {                                                       
 781                 }                                                                                        
 782             }                                                                                            
 783         }                                                                                                
 784     }                                                                                                    
 785                                                                                                          
 786     /**                                                                                                  
 787      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 788      */                                                                                                  
 789     static void moveItemInDatabase(Context context, final ItemInfo item, final long container,           
 790             final long screenId, final int cellX, final int cellY) {                                     
 791         item.container = container;                                                                      
 792         item.cellX = cellX;                                                                              
 793         item.cellY = cellY;                                                                              
 794                                                                                                          
 795         // We store hotseat items in canonical form which is this orientation invariant position         
 796         // in the hotseat                                                                                
 797         if (context instanceof Launcher && screenId < 0 &&                                               
 798                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 799             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 800         } else {                                                                                         
 801             item.screenId = screenId;                                                                    
 802         }                                                                                                
 803                                                                                                          
 804         final ContentValues values = new ContentValues();                                                
 805         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 806         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 807         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 808         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 809                                                                                                          
 810         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 811     }                                                                                                    
 812                                                                                                          
 813     /**                                                                                                  
 814      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 815      * cellX, cellY have already been updated on the ItemInfos.                                          
 816      */                                                                                                  
 817     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 818             final long container, final int screen) {                                                    
 819                                                                                                          
 820         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 821         int count = items.size();                                                                        
 822                                                                                                          
 823         for (int i = 0; i < count; i++) {                                                                
 824             ItemInfo item = items.get(i);                                                                
 825             item.container = container;                                                                  
 826                                                                                                          
 827             // We store hotseat items in canonical form which is this orientation invariant position     
 828             // in the hotseat                                                                            
 829             if (context instanceof Launcher && screen < 0 &&                                             
 830                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 831                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 832                         item.cellY);                                                                     
 833             } else {                                                                                     
 834                 item.screenId = screen;                                                                  
 835             }                                                                                            
 836                                                                                                          
 837             final ContentValues values = new ContentValues();                                            
 838             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 839             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 840             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 841             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 842                                                                                                          
 843             contentValues.add(values);                                                                   
 844         }                                                                                                
 845         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 846     }                                                                                                    
 847                                                                                                          
 848     /**                                                                                                  
 849      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 850      */                                                                                                  
 851     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 852             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 853         item.container = container;                                                                      
 854         item.cellX = cellX;                                                                              
 855         item.cellY = cellY;                                                                              
 856         item.spanX = spanX;                                                                              
 857         item.spanY = spanY;                                                                              
 858                                                                                                          
 859         // We store hotseat items in canonical form which is this orientation invariant position         
 860         // in the hotseat                                                                                
 861         if (context instanceof Launcher && screenId < 0 &&                                               
 862                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 863             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 864         } else {                                                                                         
 865             item.screenId = screenId;                                                                    
 866         }                                                                                                
 867                                                                                                          
 868         final ContentValues values = new ContentValues();                                                
 869         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 870         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 871         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 872         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 873         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 874         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 875                                                                                                          
 876         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 877     }                                                                                                    
 878                                                                                                          
 879     /**                                                                                                  
 880      * Update an item to the database in a specified container.                                          
 881      */                                                                                                  
 882     static void updateItemInDatabase(Context context, final ItemInfo item) {                             
 883         final ContentValues values = new ContentValues();                                                
 884         item.onAddToDatabase(values);                                                                    
 885         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                
 886         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 887     }                                                                                                    
 888                                                                                                          
 889     /**                                                                                                  
 890      * Returns true if the shortcuts already exists in the database.                                     
 891      * we identify a shortcut by its title and intent.                                                   
 892      */                                                                                                  
 893     static boolean shortcutExists(Context context, String title, Intent intent) {                        
 894         final ContentResolver cr = context.getContentResolver();                                         
 895         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 896             new String[] { "title", "intent" }, "title=? and intent=?",                                  
 897             new String[] { title, intent.toUri(0) }, null);                                              
 898         boolean result = false;                                                                          
 899         try {                                                                                            
 900             result = c.moveToFirst();                                                                    
 901         } finally {                                                                                      
 902             c.close();                                                                                   
 903         }                                                                                                
 904         return result;                                                                                   
 905     }                                                                                                    
 906                                                                                                          
 907     /**                                                                                                  
 908      * Returns true if the shortcuts already exists in the database.                                     
 909      * we identify a shortcut by the component name of the intent.                                       
 910      */                                                                                                  
 911     static boolean appWasRestored(Context context, Intent intent) {                                      
 912         final ContentResolver cr = context.getContentResolver();                                         
 913         final ComponentName component = intent.getComponent();                                           
 914         if (component == null) {                                                                         
 915             return false;                                                                                
 916         }                                                                                                
 917         String componentName = component.flattenToString();                                              
 918         final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1";       
 919         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 920                 new String[]{"intent", "restored"}, where, null, null);                                  
 921         boolean result = false;                                                                          
 922         try {                                                                                            
 923             result = c.moveToFirst();                                                                    
 924         } finally {                                                                                      
 925             c.close();                                                                                   
 926         }                                                                                                
 927         Log.d(TAG, "shortcutWasRestored is " + result + " for " + componentName);                        
 928         return result;                                                                                   
 929     }                                                                                                    
 930                                                                                                          
 931     /**                                                                                                  
 932      * Returns an ItemInfo array containing all the items in the LauncherModel.                          
 933      * The ItemInfo.id is not set through this function.                                                 
 934      */                                                                                                  
 935     static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {                             
 936         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
 937         final ContentResolver cr = context.getContentResolver();                                         
 938         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {                       
 939                 LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,              
 940                 LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Fav🔵
 941                 LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null); 
 942                                                                                                          
 943         final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);         
 944         final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);        
 945         final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);              
 946         final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                
 947         final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                
 948         final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                
 949         final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                
 950                                                                                                          
 951         try {                                                                                            
 952             while (c.moveToNext()) {                                                                     
 953                 ItemInfo item = new ItemInfo();                                                          
 954                 item.cellX = c.getInt(cellXIndex);                                                       
 955                 item.cellY = c.getInt(cellYIndex);                                                       
 956                 item.spanX = Math.max(1, c.getInt(spanXIndex));                                          
 957                 item.spanY = Math.max(1, c.getInt(spanYIndex));                                          
 958                 item.container = c.getInt(containerIndex);                                               
 959                 item.itemType = c.getInt(itemTypeIndex);                                                 
 960                 item.screenId = c.getInt(screenIndex);                                                   
 961                                                                                                          
 962                 items.add(item);                                                                         
 963             }                                                                                            
 964         } catch (Exception e) {                                                                          
 965             items.clear();                                                                               
 966         } finally {                                                                                      
 967             c.close();                                                                                   
 968         }                                                                                                
 969                                                                                                          
 970         return items;                                                                                    
 971     }                                                                                                    
 972                                                                                                          
 973     /**                                                                                                  
 974      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 975      */                                                                                                  
 976     FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {            
 977         final ContentResolver cr = context.getContentResolver();                                         
 978         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
 979                 "_id=? and (itemType=? or itemType=?)",                                                  
 980                 new String[] { String.valueOf(id),                                                       
 981                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
 982                                                                                                          
 983         try {                                                                                            
 984             if (c.moveToFirst()) {                                                                       
 985                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 986                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 987                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 988                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 989                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 990                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 991                                                                                                          
 992                 FolderInfo folderInfo = null;                                                            
 993                 switch (c.getInt(itemTypeIndex)) {                                                       
 994                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 995                         folderInfo = findOrMakeFolder(folderList, id);                                   
 996                         break;                                                                           
 997                 }                                                                                        
 998                                                                                                          
 999                 folderInfo.title = c.getString(titleIndex);                                              
1000                 folderInfo.id = id;                                                                      
1001                 folderInfo.container = c.getInt(containerIndex);                                         
1002                 folderInfo.screenId = c.getInt(screenIndex);                                             
1003                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
1004                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
1005                                                                                                          
1006                 return folderInfo;                                                                       
1007             }                                                                                            
1008         } finally {                                                                                      
1009             c.close();                                                                                   
1010         }                                                                                                
1011                                                                                                          
1012         return null;                                                                                     
1013     }                                                                                                    
1014                                                                                                          
1015     /**                                                                                                  
1016      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
1017      * cellY fields of the item. Also assigns an ID to the item.                                         
1018      */                                                                                                  
1019     static void addItemToDatabase(Context context, final ItemInfo item, final long container,            
1020             final long screenId, final int cellX, final int cellY, final boolean notify) {               
1021         item.container = container;                                                                      
1022         item.cellX = cellX;                                                                              
1023         item.cellY = cellY;                                                                              
1024         // We store hotseat items in canonical form which is this orientation invariant position         
1025         // in the hotseat                                                                                
1026         if (context instanceof Launcher && screenId < 0 &&                                               
1027                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
1028             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1029         } else {                                                                                         
1030             item.screenId = screenId;                                                                    
1031         }                                                                                                
1032                                                                                                          
1033         final ContentValues values = new ContentValues();                                                
1034         final ContentResolver cr = context.getContentResolver();                                         
1035         item.onAddToDatabase(values);                                                                    
1036                                                                                                          
1037         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
1038         values.put(LauncherSettings.Favorites._ID, item.id);                                             
1039         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                
1040                                                                                                          
1041         Runnable r = new Runnable() {                                                                    
1042             public void run() {                                                                          
1043                 cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                              
1044                         LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                 
1045                                                                                                          
1046                 // Lock on mBgLock *after* the db operation                                              
1047                 synchronized (sBgLock) {                                                                 
1048                     checkItemInfoLocked(item.id, item, null);                                            
1049                     sBgItemsIdMap.put(item.id, item);                                                    
1050                     switch (item.itemType) {                                                             
1051                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1052                             sBgFolders.put(item.id, (FolderInfo) item);                                  
1053                             // Fall through                                                              
1054                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1055                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1056                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
1057                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
1058                                 sBgWorkspaceItems.add(item);                                             
1059                             } else {                                                                     
1060                                 if (!sBgFolders.containsKey(item.container)) {                           
1061                                     // Adding an item to a folder that doesn't exist.                    
1062                                     String msg = "adding item: " + item + " to a folder that " +         
1063                                             " doesn't exist";                                            
1064                                     Log.e(TAG, msg);                                                     
1065                                 }                                                                        
1066                             }                                                                            
1067                             break;                                                                       
1068                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1069                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
1070                             break;                                                                       
1071                     }                                                                                    
1072                 }                                                                                        
1073             }                                                                                            
1074         };                                                                                               
1075         runOnWorkerThread(r);                                                                            
1076     }                                                                                                    
1077                                                                                                          
1078     /**                                                                                                  
1079      * Creates a new unique child id, for a given cell span across all layouts.                          
1080      */                                                                                                  
1081     static int getCellLayoutChildId(                                                                     
1082             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
1083         return (((int) container & 0xFF) << 24)                                                          
1084                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1085     }                                                                                                    
1086                                                                                                          
1087     /**                                                                                                  
1088      * Removes the specified item from the database                                                      
1089      * @param context                                                                                    
1090      * @param item                                                                                       
1091      */                                                                                                  
1092     static void deleteItemFromDatabase(Context context, final ItemInfo item) {                           
1093         final ContentResolver cr = context.getContentResolver();                                         
1094         final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);                
1095                                                                                                          
1096         Runnable r = new Runnable() {                                                                    
1097             public void run() {                                                                          
1098                 cr.delete(uriToDelete, null, null);                                                      
1099                                                                                                          
1100                 // Lock on mBgLock *after* the db operation                                              
1101                 synchronized (sBgLock) {                                                                 
1102                     switch (item.itemType) {                                                             
1103                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1104                             sBgFolders.remove(item.id);                                                  
1105                             for (ItemInfo info: sBgItemsIdMap.values()) {                                
1106                                 if (info.container == item.id) {                                         
1107                                     // We are deleting a folder which still contains items that          
1108                                     // think they are contained by that folder.                          
1109                                     String msg = "deleting a folder (" + item + ") which still " +       
1110                                             "contains items (" + info + ")";                             
1111                                     Log.e(TAG, msg);                                                     
1112                                 }                                                                        
1113                             }                                                                            
1114                             sBgWorkspaceItems.remove(item);                                              
1115                             break;                                                                       
1116                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1117                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1118                             sBgWorkspaceItems.remove(item);                                              
1119                             break;                                                                       
1120                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1121                             sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                          
1122                             break;                                                                       
1123                     }                                                                                    
1124                     sBgItemsIdMap.remove(item.id);                                                       
1125                     sBgDbIconCache.remove(item);                                                         
1126                 }                                                                                        
1127             }                                                                                            
1128         };                                                                                               
1129         runOnWorkerThread(r);                                                                            
1130     }                                                                                                    
1131                                                                                                          
1132     /**                                                                                                  
1133      * Update the order of the workspace screens in the database. The array list contains                
1134      * a list of screen ids in the order that they should appear.                                        
1135      */                                                                                                  
1136     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1137         // Log to disk                                                                                   
1138         Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                       
1139         Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);        
1140                                                                                                          
1141         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1142         final ContentResolver cr = context.getContentResolver();                                         
1143         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1144                                                                                                          
1145         // Remove any negative screen ids -- these aren't persisted                                      
1146         Iterator<Long> iter = screensCopy.iterator();                                                    
1147         while (iter.hasNext()) {                                                                         
1148             long id = iter.next();                                                                       
1149             if (id < 0) {                                                                                
1150                 iter.remove();                                                                           
1151             }                                                                                            
1152         }                                                                                                
1153                                                                                                          
1154         Runnable r = new Runnable() {                                                                    
1155             @Override                                                                                    
1156             public void run() {                                                                          
1157                 // Clear the table                                                                       
1158                 cr.delete(uri, null, null);                                                              
1159                 int count = screensCopy.size();                                                          
1160                 ContentValues[] values = new ContentValues[count];                                       
1161                 for (int i = 0; i < count; i++) {                                                        
1162                     ContentValues v = new ContentValues();                                               
1163                     long screenId = screensCopy.get(i);                                                  
1164                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1165                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1166                     values[i] = v;                                                                       
1167                 }                                                                                        
1168                 cr.bulkInsert(uri, values);                                                              
1169                                                                                                          
1170                 synchronized (sBgLock) {                                                                 
1171                     sBgWorkspaceScreens.clear();                                                         
1172                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1173                 }                                                                                        
1174             }                                                                                            
1175         };                                                                                               
1176         runOnWorkerThread(r);                                                                            
1177     }                                                                                                    
1178                                                                                                          
1179     /**                                                                                                  
1180      * Remove the contents of the specified folder from the database                                     
1181      */                                                                                                  
1182     static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {               
1183         final ContentResolver cr = context.getContentResolver();                                         
1184                                                                                                          
1185         Runnable r = new Runnable() {                                                                    
1186             public void run() {                                                                          
1187                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);         
1188                 // Lock on mBgLock *after* the db operation                                              
1189                 synchronized (sBgLock) {                                                                 
1190                     sBgItemsIdMap.remove(info.id);                                                       
1191                     sBgFolders.remove(info.id);                                                          
1192                     sBgDbIconCache.remove(info);                                                         
1193                     sBgWorkspaceItems.remove(info);                                                      
1194                 }                                                                                        
1195                                                                                                          
1196                 cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                        
1197                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                     
1198                 // Lock on mBgLock *after* the db operation                                              
1199                 synchronized (sBgLock) {                                                                 
1200                     for (ItemInfo childInfo : info.contents) {                                           
1201                         sBgItemsIdMap.remove(childInfo.id);                                              
1202                         sBgDbIconCache.remove(childInfo);                                                
1203                     }                                                                                    
1204                 }                                                                                        
1205             }                                                                                            
1206         };                                                                                               
1207         runOnWorkerThread(r);                                                                            
1208     }                                                                                                    
1209                                                                                                          
1210     /**                                                                                                  
1211      * Set this as the current Launcher activity object for the loader.                                  
1212      */                                                                                                  
1213     public void initialize(Callbacks callbacks) {                                                        
1214         synchronized (mLock) {                                                                           
1215             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1216         }                                                                                                
1217     }                                                                                                    
1218                                                                                                          
1219     /**                                                                                                  
1220      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1221      * ACTION_PACKAGE_CHANGED.                                                                           
1222      */                                                                                                  
1223     @Override                                                                                            
1224     public void onReceive(Context context, Intent intent) {                                              
1225         if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);                                     
1226                                                                                                          
1227         final String action = intent.getAction();                                                        
1228                                                                                                          
1229         if (Intent.ACTION_PACKAGE_CHANGED.equals(action)                                                 
1230                 || Intent.ACTION_PACKAGE_REMOVED.equals(action)                                          
1231                 || Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                         
1232             final String packageName = intent.getData().getSchemeSpecificPart();                         
1233             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1234                                                                                                          
1235             int op = PackageUpdatedTask.OP_NONE;                                                         
1236                                                                                                          
1237             if (packageName == null || packageName.length() == 0) {                                      
1238                 // they sent us a bad intent                                                             
1239                 return;                                                                                  
1240             }                                                                                            
1241                                                                                                          
1242             if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {                                          
1243                 op = PackageUpdatedTask.OP_UPDATE;                                                       
1244             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {                                   
1245                 if (!replacing) {                                                                        
1246                     op = PackageUpdatedTask.OP_REMOVE;                                                   
1247                 }                                                                                        
1248                 // else, we are replacing the package, so a PACKAGE_ADDED will be sent                   
1249                 // later, we will update the package at this time                                        
1250             } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                     
1251                 if (!replacing) {                                                                        
1252                     op = PackageUpdatedTask.OP_ADD;                                                      
1253                 } else {                                                                                 
1254                     op = PackageUpdatedTask.OP_UPDATE;                                                   
1255                 }                                                                                        
1256             }                                                                                            
1257                                                                                                          
1258             if (op != PackageUpdatedTask.OP_NONE) {                                                      
1259                 enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));         
1260             }                                                                                            
1261                                                                                                          
1262         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {                       
1263             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1264             String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);           
1265             if (!replacing) {                                                                            
1266                 enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));      
1267                 if (mAppsCanBeOnRemoveableStorage) {                                                     
1268                     // Only rebind if we support removable storage.  It catches the case where           
1269                     // apps on the external sd card need to be reloaded                                  
1270                     startLoaderFromBackground();                                                         
1271                 }                                                                                        
1272             } else {                                                                                     
1273                 // If we are replacing then just update the packages in the list                         
1274                 enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,               
1275                         packages));                                                                      
1276             }                                                                                            
1277         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {                     
1278             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1279             if (!replacing) {                                                                            
1280                 String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);       
1281                 enqueuePackageUpdated(new PackageUpdatedTask(                                            
1282                             PackageUpdatedTask.OP_UNAVAILABLE, packages));                               
1283             }                                                                                            
1284             // else, we are replacing the packages, so ignore this event and wait for                    
1285             // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time                       
1286         } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                        
1287             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1288             forceReload();                                                                               
1289         } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                 
1290              // Check if configuration change was an mcc/mnc change which would affect app resources     
1291              // and we would need to clear out the labels in all apps/workspace. Same handling as        
1292              // above for ACTION_LOCALE_CHANGED                                                          
1293              Configuration currentConfig = context.getResources().getConfiguration();                    
1294              if (mPreviousConfigMcc != currentConfig.mcc) {                                              
1295                    Log.d(TAG, "Reload apps on config change. curr_mcc:"                                  
1296                        + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                          
1297                    forceReload();                                                                        
1298              }                                                                                           
1299              // Update previousConfig                                                                    
1300              mPreviousConfigMcc = currentConfig.mcc;                                                     
1301         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1302                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1303             if (mCallbacks != null) {                                                                    
1304                 Callbacks callbacks = mCallbacks.get();                                                  
1305                 if (callbacks != null) {                                                                 
1306                     callbacks.bindSearchablesChanged();                                                  
1307                 }                                                                                        
1308             }                                                                                            
1309         }                                                                                                
1310     }                                                                                                    
1311                                                                                                          
1312     private void forceReload() {                                                                         
1313         resetLoadedState(true, true);                                                                    
1314                                                                                                          
1315         // Do this here because if the launcher activity is running it will be restarted.                
1316         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1317         // to reload.                                                                                    
1318         startLoaderFromBackground();                                                                     
1319     }                                                                                                    
1320                                                                                                          
1321     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1322         synchronized (mLock) {                                                                           
1323             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1324             // mWorkspaceLoaded to true later                                                            
1325             stopLoaderLocked();                                                                          
1326             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1327             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1328         }                                                                                                
1329     }                                                                                                    
1330                                                                                                          
1331     /**                                                                                                  
1332      * When the launcher is in the background, it's possible for it to miss paired                       
1333      * configuration changes.  So whenever we trigger the loader from the background                     
1334      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1335      * of doing it now.                                                                                  
1336      */                                                                                                  
1337     public void startLoaderFromBackground() {                                                            
1338         boolean runLoader = false;                                                                       
1339         if (mCallbacks != null) {                                                                        
1340             Callbacks callbacks = mCallbacks.get();                                                      
1341             if (callbacks != null) {                                                                     
1342                 // Only actually run the loader if they're not paused.                                   
1343                 if (!callbacks.setLoadOnResume()) {                                                      
1344                     runLoader = true;                                                                    
1345                 }                                                                                        
1346             }                                                                                            
1347         }                                                                                                
1348         if (runLoader) {                                                                                 
1349             startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                          
1350         }                                                                                                
1351     }                                                                                                    
1352                                                                                                          
1353     // If there is already a loader task running, tell it to stop.                                       
1354     // returns true if isLaunching() was true on the old task                                            
1355     private boolean stopLoaderLocked() {                                                                 
1356         boolean isLaunching = false;                                                                     
1357         LoaderTask oldTask = mLoaderTask;                                                                
1358         if (oldTask != null) {                                                                           
1359             if (oldTask.isLaunching()) {                                                                 
1360                 isLaunching = true;                                                                      
1361             }                                                                                            
1362             oldTask.stopLocked();                                                                        
1363         }                                                                                                
1364         return isLaunching;                                                                              
1365     }                                                                                                    
1366                                                                                                          
1367     public void startLoader(boolean isLaunching, int synchronousBindPage) {                              
1368         startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                 
1369     }                                                                                                    
1370                                                                                                          
1371     public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {               
1372         synchronized (mLock) {                                                                           
1373             if (DEBUG_LOADERS) {                                                                         
1374                 Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                    
1375             }                                                                                            
1376                                                                                                          
1377             // Clear any deferred bind-runnables from the synchronized load process                      
1378             // We must do this before any loading/binding is scheduled below.                            
1379             mDeferredBindRunnables.clear();                                                              
1380                                                                                                          
1381             // Don't bother to start the thread if we know it's not going to do anything                 
1382             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1383                 // If there is already one running, tell it to stop.                                     
1384                 // also, don't downgrade isLaunching if we're already running                            
1385                 isLaunching = isLaunching || stopLoaderLocked();                                         
1386                 mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                 
1387                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1388                         && mAllAppsLoaded && mWorkspaceLoaded) {                                         
1389                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1390                 } else {                                                                                 
1391                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1392                     sWorker.post(mLoaderTask);                                                           
1393                 }                                                                                        
1394             }                                                                                            
1395         }                                                                                                
1396     }                                                                                                    
1397                                                                                                          
1398     void bindRemainingSynchronousPages() {                                                               
1399         // Post the remaining side pages to be loaded                                                    
1400         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1401             for (final Runnable r : mDeferredBindRunnables) {                                            
1402                 mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                          
1403             }                                                                                            
1404             mDeferredBindRunnables.clear();                                                              
1405         }                                                                                                
1406     }                                                                                                    
1407                                                                                                          
1408     public void stopLoader() {                                                                           
1409         synchronized (mLock) {                                                                           
1410             if (mLoaderTask != null) {                                                                   
1411                 mLoaderTask.stopLocked();                                                                
1412             }                                                                                            
1413         }                                                                                                
1414     }                                                                                                    
1415                                                                                                          
1416     /** Loads the workspace screens db into a map of Rank -> ScreenId */                                 
1417     private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {                      
1418         final ContentResolver contentResolver = context.getContentResolver();                            
1419         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1420         final Cursor sc = contentResolver.query(screensUri, null, null, null, null);                     
1421         TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();                            
1422                                                                                                          
1423         try {                                                                                            
1424             final int idIndex = sc.getColumnIndexOrThrow(                                                
1425                     LauncherSettings.WorkspaceScreens._ID);                                              
1426             final int rankIndex = sc.getColumnIndexOrThrow(                                              
1427                     LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                      
1428             while (sc.moveToNext()) {                                                                    
1429                 try {                                                                                    
1430                     long screenId = sc.getLong(idIndex);                                                 
1431                     int rank = sc.getInt(rankIndex);                                                     
1432                     orderedScreens.put(rank, screenId);                                                  
1433                 } catch (Exception e) {                                                                  
1434                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e,🔵
1435                 }                                                                                        
1436             }                                                                                            
1437         } finally {                                                                                      
1438             sc.close();                                                                                  
1439         }                                                                                                
1440                                                                                                          
1441         // Log to disk                                                                                   
1442         Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);                           
1443         ArrayList<String> orderedScreensPairs= new ArrayList<String>();                                  
1444         for (Integer i : orderedScreens.keySet()) {                                                      
1445             orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");                     
1446         }                                                                                                
1447         Launcher.addDumpLog(TAG, "11683562 -   screens: " +                                              
1448                 TextUtils.join(", ", orderedScreensPairs), true);                                        
1449         return orderedScreens;                                                                           
1450     }                                                                                                    
1451                                                                                                          
1452     public boolean isAllAppsLoaded() {                                                                   
1453         return mAllAppsLoaded;                                                                           
1454     }                                                                                                    
1455                                                                                                          
1456     boolean isLoadingWorkspace() {                                                                       
1457         synchronized (mLock) {                                                                           
1458             if (mLoaderTask != null) {                                                                   
1459                 return mLoaderTask.isLoadingWorkspace();                                                 
1460             }                                                                                            
1461         }                                                                                                
1462         return false;                                                                                    
1463     }                                                                                                    
1464                                                                                                          
1465     /**                                                                                                  
1466      * Runnable for the thread that loads the contents of the launcher:                                  
1467      *   - workspace icons                                                                               
1468      *   - widgets                                                                                       
1469      *   - all apps icons                                                                                
1470      */                                                                                                  
1471     private class LoaderTask implements Runnable {                                                       
1472         private Context mContext;                                                                        
1473         private boolean mIsLaunching;                                                                    
1474         private boolean mIsLoadingAndBindingWorkspace;                                                   
1475         private boolean mStopped;                                                                        
1476         private boolean mLoadAndBindStepFinished;                                                        
1477         private int mFlags;                                                                              
1478                                                                                                          
1479         private HashMap<Object, CharSequence> mLabelCache;                                               
1480                                                                                                          
1481         LoaderTask(Context context, boolean isLaunching, int flags) {                                    
1482             mContext = context;                                                                          
1483             mIsLaunching = isLaunching;                                                                  
1484             mLabelCache = new HashMap<Object, CharSequence>();                                           
1485             mFlags = flags;                                                                              
1486         }                                                                                                
1487                                                                                                          
1488         boolean isLaunching() {                                                                          
1489             return mIsLaunching;                                                                         
1490         }                                                                                                
1491                                                                                                          
1492         boolean isLoadingWorkspace() {                                                                   
1493             return mIsLoadingAndBindingWorkspace;                                                        
1494         }                                                                                                
1495                                                                                                          
1496         /** Returns whether this is an upgrade path */                                                   
1497         private boolean loadAndBindWorkspace() {                                                         
1498             mIsLoadingAndBindingWorkspace = true;                                                        
1499                                                                                                          
1500             // Load the workspace                                                                        
1501             if (DEBUG_LOADERS) {                                                                         
1502                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1503             }                                                                                            
1504                                                                                                          
1505             boolean isUpgradePath = false;                                                               
1506             if (!mWorkspaceLoaded) {                                                                     
1507                 isUpgradePath = loadWorkspace();                                                         
1508                 synchronized (LoaderTask.this) {                                                         
1509                     if (mStopped) {                                                                      
1510                         return isUpgradePath;                                                            
1511                     }                                                                                    
1512                     mWorkspaceLoaded = true;                                                             
1513                 }                                                                                        
1514             }                                                                                            
1515                                                                                                          
1516             // Bind the workspace                                                                        
1517             bindWorkspace(-1, isUpgradePath);                                                            
1518             return isUpgradePath;                                                                        
1519         }                                                                                                
1520                                                                                                          
1521         private void waitForIdle() {                                                                     
1522             // Wait until the either we're stopped or the other threads are done.                        
1523             // This way we don't start loading all apps until the workspace has settled                  
1524             // down.                                                                                     
1525             synchronized (LoaderTask.this) {                                                             
1526                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1527                                                                                                          
1528                 mHandler.postIdle(new Runnable() {                                                       
1529                         public void run() {                                                              
1530                             synchronized (LoaderTask.this) {                                             
1531                                 mLoadAndBindStepFinished = true;                                         
1532                                 if (DEBUG_LOADERS) {                                                     
1533                                     Log.d(TAG, "done with previous binding step");                       
1534                                 }                                                                        
1535                                 LoaderTask.this.notify();                                                
1536                             }                                                                            
1537                         }                                                                                
1538                     });                                                                                  
1539                                                                                                          
1540                 while (!mStopped && !mLoadAndBindStepFinished && !mFlushingWorkerThread) {               
1541                     try {                                                                                
1542                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1543                         // wait no longer than 1sec at a time                                            
1544                         this.wait(1000);                                                                 
1545                     } catch (InterruptedException ex) {                                                  
1546                         // Ignore                                                                        
1547                     }                                                                                    
1548                 }                                                                                        
1549                 if (DEBUG_LOADERS) {                                                                     
1550                     Log.d(TAG, "waited "                                                                 
1551                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1552                             + "ms for previous step to finish binding");                                 
1553                 }                                                                                        
1554             }                                                                                            
1555         }                                                                                                
1556                                                                                                          
1557         void runBindSynchronousPage(int synchronousBindPage) {                                           
1558             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1559                 // Ensure that we have a valid page index to load synchronously                          
1560                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1561                         "valid page index");                                                             
1562             }                                                                                            
1563             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1564                 // Ensure that we don't try and bind a specified page when the pages have not been       
1565                 // loaded already (we should load everything asynchronously in that case)                
1566                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1567             }                                                                                            
1568             synchronized (mLock) {                                                                       
1569                 if (mIsLoaderTaskRunning) {                                                              
1570                     // Ensure that we are never running the background loading at this point since       
1571                     // we also touch the background collections                                          
1572                     throw new RuntimeException("Error! Background loading is already running");          
1573                 }                                                                                        
1574             }                                                                                            
1575                                                                                                          
1576             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1577             //      data structures, we can't allow any other thread to touch that data, but because     
1578             //      this call is synchronous, we can get away with not locking).                         
1579                                                                                                          
1580             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1581             // operations from the previous activity.  We need to ensure that all queued operations      
1582             // are executed before any synchronous binding work is done.                                 
1583             mHandler.flush();                                                                            
1584                                                                                                          
1585             // Divide the set of loaded items into those that we are binding synchronously, and          
1586             // everything else that is to be bound normally (asynchronously).                            
1587             bindWorkspace(synchronousBindPage, false);                                                   
1588             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1589             //      arise from that.                                                                     
1590             onlyBindAllApps();                                                                           
1591         }                                                                                                
1592                                                                                                          
1593         public void run() {                                                                              
1594             boolean isUpgrade = false;                                                                   
1595                                                                                                          
1596             synchronized (mLock) {                                                                       
1597                 mIsLoaderTaskRunning = true;                                                             
1598             }                                                                                            
1599             // Optimize for end-user experience: if the Launcher is up and // running with the           
1600             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1601             // workspace first (default).                                                                
1602             keep_running: {                                                                              
1603                 // Elevate priority when Home launches for the first time to avoid                       
1604                 // starving at boot time. Staring at a blank home is not cool.                           
1605                 synchronized (mLock) {                                                                   
1606                     if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                        
1607                             (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                  
1608                     android.os.Process.setThreadPriority(mIsLaunching                                    
1609                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);     
1610                 }                                                                                        
1611                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1612                 isUpgrade = loadAndBindWorkspace();                                                      
1613                                                                                                          
1614                 if (mStopped) {                                                                          
1615                     break keep_running;                                                                  
1616                 }                                                                                        
1617                                                                                                          
1618                 // Whew! Hard work done.  Slow us down, and wait until the UI thread has                 
1619                 // settled down.                                                                         
1620                 synchronized (mLock) {                                                                   
1621                     if (mIsLaunching) {                                                                  
1622                         if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");          
1623                         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        
1624                     }                                                                                    
1625                 }                                                                                        
1626                 waitForIdle();                                                                           
1627                                                                                                          
1628                 // second step                                                                           
1629                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1630                 loadAndBindAllApps();                                                                    
1631                                                                                                          
1632                 // Restore the default thread priority after we are done loading items                   
1633                 synchronized (mLock) {                                                                   
1634                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);               
1635                 }                                                                                        
1636             }                                                                                            
1637                                                                                                          
1638             // Update the saved icons if necessary                                                       
1639             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1640             synchronized (sBgLock) {                                                                     
1641                 for (Object key : sBgDbIconCache.keySet()) {                                             
1642                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1643                 }                                                                                        
1644                 sBgDbIconCache.clear();                                                                  
1645             }                                                                                            
1646                                                                                                          
1647             if (LauncherAppState.isDisableAllApps()) {                                                   
1648                 // Ensure that all the applications that are in the system are                           
1649                 // represented on the home screen.                                                       
1650                 if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {                                       
1651                     verifyApplications();                                                                
1652                 }                                                                                        
1653             }                                                                                            
1654                                                                                                          
1655             // Clear out this reference, otherwise we end up holding it until all of the                 
1656             // callback runnables are done.                                                              
1657             mContext = null;                                                                             
1658                                                                                                          
1659             synchronized (mLock) {                                                                       
1660                 // If we are still the last one to be scheduled, remove ourselves.                       
1661                 if (mLoaderTask == this) {                                                               
1662                     mLoaderTask = null;                                                                  
1663                 }                                                                                        
1664                 mIsLoaderTaskRunning = false;                                                            
1665             }                                                                                            
1666         }                                                                                                
1667                                                                                                          
1668         public void stopLocked() {                                                                       
1669             synchronized (LoaderTask.this) {                                                             
1670                 mStopped = true;                                                                         
1671                 this.notify();                                                                           
1672             }                                                                                            
1673         }                                                                                                
1674                                                                                                          
1675         /**                                                                                              
1676          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1677          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1678          * object that was around when the deferred message was scheduled, and if there's                
1679          * a new Callbacks object around then also return null.  This will save us from                  
1680          * calling onto it with data that will be ignored.                                               
1681          */                                                                                              
1682         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1683             synchronized (mLock) {                                                                       
1684                 if (mStopped) {                                                                          
1685                     return null;                                                                         
1686                 }                                                                                        
1687                                                                                                          
1688                 if (mCallbacks == null) {                                                                
1689                     return null;                                                                         
1690                 }                                                                                        
1691                                                                                                          
1692                 final Callbacks callbacks = mCallbacks.get();                                            
1693                 if (callbacks != oldCallbacks) {                                                         
1694                     return null;                                                                         
1695                 }                                                                                        
1696                 if (callbacks == null) {                                                                 
1697                     Log.w(TAG, "no mCallbacks");                                                         
1698                     return null;                                                                         
1699                 }                                                                                        
1700                                                                                                          
1701                 return callbacks;                                                                        
1702             }                                                                                            
1703         }                                                                                                
1704                                                                                                          
1705         private void verifyApplications() {                                                              
1706             final Context context = mApp.getContext();                                                   
1707                                                                                                          
1708             // Cross reference all the applications in our apps list with items in the workspace         
1709             ArrayList<ItemInfo> tmpInfos;                                                                
1710             ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                       
1711             synchronized (sBgLock) {                                                                     
1712                 for (AppInfo app : mBgAllAppsList.data) {                                                
1713                     tmpInfos = getItemInfoForComponentName(app.componentName);                           
1714                     if (tmpInfos.isEmpty()) {                                                            
1715                         // We are missing an application icon, so add this to the workspace              
1716                         added.add(app);                                                                  
1717                         // This is a rare event, so lets log it                                          
1718                         Log.e(TAG, "Missing Application on load: " + app);                               
1719                     }                                                                                    
1720                 }                                                                                        
1721             }                                                                                            
1722             if (!added.isEmpty()) {                                                                      
1723                 Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                             
1724                 addAndBindAddedApps(context, added, cb, new ArrayList<AppInfo>());                       
1725             }                                                                                            
1726         }                                                                                                
1727                                                                                                          
1728         // check & update map of what's occupied; used to discard overlapping/invalid items              
1729         private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item,          
1730                                            AtomicBoolean deleteOnInvalidPlacement) {                     
1731             LauncherAppState app = LauncherAppState.getInstance();                                       
1732             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1733             final int countX = (int) grid.numColumns;                                                    
1734             final int countY = (int) grid.numRows;                                                       
1735                                                                                                          
1736             long containerIndex = item.screenId;                                                         
1737             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1738                 // Return early if we detect that an item is under the hotseat button                    
1739                 if (mCallbacks == null ||                                                                
1740                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1741                     deleteOnInvalidPlacement.set(true);                                                  
1742                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1743                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1744                             + item.cellY + ") occupied by all apps");                                    
1745                     return false;                                                                        
1746                 }                                                                                        
1747                                                                                                          
1748                 final ItemInfo[][] hotseatItems =                                                        
1749                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1750                                                                                                          
1751                 if (item.screenId >= grid.numHotseatIcons) {                                             
1752                     Log.e(TAG, "Error loading shortcut " + item                                          
1753                             + " into hotseat position " + item.screenId                                  
1754                             + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)            
1755                             + ")");                                                                      
1756                     return false;                                                                        
1757                 }                                                                                        
1758                                                                                                          
1759                 if (hotseatItems != null) {                                                              
1760                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1761                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1762                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1763                                 + item.cellY + ") occupied by "                                          
1764                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1765                                 [(int) item.screenId][0]);                                               
1766                             return false;                                                                
1767                     } else {                                                                             
1768                         hotseatItems[(int) item.screenId][0] = item;                                     
1769                         return true;                                                                     
1770                     }                                                                                    
1771                 } else {                                                                                 
1772                     final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];              
1773                     items[(int) item.screenId][0] = item;                                                
1774                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1775                     return true;                                                                         
1776                 }                                                                                        
1777             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1778                 // Skip further checking if it is not the hotseat or workspace container                 
1779                 return true;                                                                             
1780             }                                                                                            
1781                                                                                                          
1782             if (!occupied.containsKey(item.screenId)) {                                                  
1783                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1784                 occupied.put(item.screenId, items);                                                      
1785             }                                                                                            
1786                                                                                                          
1787             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1788             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1789                     item.cellX < 0 || item.cellY < 0 ||                                                  
1790                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1791                 Log.e(TAG, "Error loading shortcut " + item                                              
1792                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1793                         + item.cellX + "," + item.cellY                                                  
1794                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1795                 return false;                                                                            
1796             }                                                                                            
1797                                                                                                          
1798             // Check if any workspace icons overlap with each other                                      
1799             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1800                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1801                     if (screens[x][y] != null) {                                                         
1802                         Log.e(TAG, "Error loading shortcut " + item                                      
1803                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1804                             + x + "," + y                                                                
1805                             + ") occupied by "                                                           
1806                             + screens[x][y]);                                                            
1807                         return false;                                                                    
1808                     }                                                                                    
1809                 }                                                                                        
1810             }                                                                                            
1811             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1812                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1813                     screens[x][y] = item;                                                                
1814                 }                                                                                        
1815             }                                                                                            
1816                                                                                                          
1817             return true;                                                                                 
1818         }                                                                                                
1819                                                                                                          
1820         /** Clears all the sBg data structures */                                                        
1821         private void clearSBgDataStructures() {                                                          
1822             synchronized (sBgLock) {                                                                     
1823                 sBgWorkspaceItems.clear();                                                               
1824                 sBgAppWidgets.clear();                                                                   
1825                 sBgFolders.clear();                                                                      
1826                 sBgItemsIdMap.clear();                                                                   
1827                 sBgDbIconCache.clear();                                                                  
1828                 sBgWorkspaceScreens.clear();                                                             
1829             }                                                                                            
1830         }                                                                                                
1831                                                                                                          
1832         /** Returns whether this is an upgrade path */                                                   
1833         private boolean loadWorkspace() {                                                                
1834             // Log to disk                                                                               
1835             Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                
1836                                                                                                          
1837             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                               
1838                                                                                                          
1839             final Context context = mContext;                                                            
1840             final ContentResolver contentResolver = context.getContentResolver();                        
1841             final PackageManager manager = context.getPackageManager();                                  
1842             final AppWidgetManager widgets = AppWidgetManager.getInstance(context);                      
1843             final boolean isSafeMode = manager.isSafeMode();                                             
1844                                                                                                          
1845             LauncherAppState app = LauncherAppState.getInstance();                                       
1846             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1847             int countX = (int) grid.numColumns;                                                          
1848             int countY = (int) grid.numRows;                                                             
1849                                                                                                          
1850             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1851                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1852                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1853             }                                                                                            
1854                                                                                                          
1855             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1856                 // append the user's Launcher2 shortcuts                                                 
1857                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1858                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1859             } else {                                                                                     
1860                 // Make sure the default workspace is loaded                                             
1861                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1862                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);               
1863             }                                                                                            
1864                                                                                                          
1865             // Check if we need to do any upgrade-path logic                                             
1866             // (Includes having just imported default favorites)                                         
1867             boolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb();              
1868                                                                                                          
1869             // Log to disk                                                                               
1870             Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);                  
1871                                                                                                          
1872             synchronized (sBgLock) {                                                                     
1873                 clearSBgDataStructures();                                                                
1874                                                                                                          
1875                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1876                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1877                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                           
1878                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                       
1879                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1880                                                                                                          
1881                 // +1 for the hotseat (it can be larger than the workspace)                              
1882                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1883                 // before any earlier duplicates)                                                        
1884                 final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();          
1885                                                                                                          
1886                 try {                                                                                    
1887                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1888                     final int intentIndex = c.getColumnIndexOrThrow                                      
1889                             (LauncherSettings.Favorites.INTENT);                                         
1890                     final int titleIndex = c.getColumnIndexOrThrow                                       
1891                             (LauncherSettings.Favorites.TITLE);                                          
1892                     final int iconTypeIndex = c.getColumnIndexOrThrow(                                   
1893                             LauncherSettings.Favorites.ICON_TYPE);                                       
1894                     final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);      
1895                     final int iconPackageIndex = c.getColumnIndexOrThrow(                                
1896                             LauncherSettings.Favorites.ICON_PACKAGE);                                    
1897                     final int iconResourceIndex = c.getColumnIndexOrThrow(                               
1898                             LauncherSettings.Favorites.ICON_RESOURCE);                                   
1899                     final int containerIndex = c.getColumnIndexOrThrow(                                  
1900                             LauncherSettings.Favorites.CONTAINER);                                       
1901                     final int itemTypeIndex = c.getColumnIndexOrThrow(                                   
1902                             LauncherSettings.Favorites.ITEM_TYPE);                                       
1903                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                
1904                             LauncherSettings.Favorites.APPWIDGET_ID);                                    
1905                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                          
1906                             LauncherSettings.Favorites.APPWIDGET_PROVIDER);                              
1907                     final int screenIndex = c.getColumnIndexOrThrow(                                     
1908                             LauncherSettings.Favorites.SCREEN);                                          
1909                     final int cellXIndex = c.getColumnIndexOrThrow                                       
1910                             (LauncherSettings.Favorites.CELLX);                                          
1911                     final int cellYIndex = c.getColumnIndexOrThrow                                       
1912                             (LauncherSettings.Favorites.CELLY);                                          
1913                     final int spanXIndex = c.getColumnIndexOrThrow                                       
1914                             (LauncherSettings.Favorites.SPANX);                                          
1915                     final int spanYIndex = c.getColumnIndexOrThrow(                                      
1916                             LauncherSettings.Favorites.SPANY);                                           
1917                     final int restoredIndex = c.getColumnIndexOrThrow(                                   
1918                             LauncherSettings.Favorites.RESTORED);                                        
1919                     //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);      
1920                     //final int displayModeIndex = c.getColumnIndexOrThrow(                              
1921                     //        LauncherSettings.Favorites.DISPLAY_MODE);                                  
1922                                                                                                          
1923                     ShortcutInfo info;                                                                   
1924                     String intentDescription;                                                            
1925                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1926                     int container;                                                                       
1927                     long id;                                                                             
1928                     Intent intent;                                                                       
1929                                                                                                          
1930                     while (!mStopped && c.moveToNext()) {                                                
1931                         AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);               
1932                         try {                                                                            
1933                             int itemType = c.getInt(itemTypeIndex);                                      
1934                             boolean restored = 0 != c.getInt(restoredIndex);                             
1935                                                                                                          
1936                             switch (itemType) {                                                          
1937                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
1938                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
1939                                 id = c.getLong(idIndex);                                                 
1940                                 intentDescription = c.getString(intentIndex);                            
1941                                 try {                                                                    
1942                                     intent = Intent.parseUri(intentDescription, 0);                      
1943                                     ComponentName cn = intent.getComponent();                            
1944                                     if (cn != null && !isValidPackageComponent(manager, cn)) {           
1945                                         if (restored) {                                                  
1946                                             // might be installed later                                  
1947                                             Launcher.addDumpLog(TAG,                                     
1948                                                     "package not yet restored: " + cn, true);            
1949                                         } else {                                                         
1950                                             if (!mAppsCanBeOnRemoveableStorage) {                        
1951                                                 // Log the invalid package, and remove it                
1952                                                 Launcher.addDumpLog(TAG,                                 
1953                                                         "Invalid package removed: " + cn, true);         
1954                                                 itemsToRemove.add(id);                                   
1955                                             } else {                                                     
1956                                                 // If apps can be on external storage, then we just      
1957                                                 // leave them for the user to remove (maybe add          
1958                                                 // visual treatment to it)                               
1959                                                 Launcher.addDumpLog(TAG,                                 
1960                                                         "Invalid package found: " + cn, true);           
1961                                             }                                                            
1962                                             continue;                                                    
1963                                         }                                                                
1964                                     } else if (restored) {                                               
1965                                         // no special handling necessary for this restored item          
1966                                         restoredRows.add(id);                                            
1967                                         restored = false;                                                
1968                                     }                                                                    
1969                                 } catch (URISyntaxException e) {                                         
1970                                     Launcher.addDumpLog(TAG,                                             
1971                                             "Invalid uri: " + intentDescription, true);                  
1972                                     continue;                                                            
1973                                 }                                                                        
1974                                                                                                          
1975                                 if (restored) {                                                          
1976                                     Launcher.addDumpLog(TAG,                                             
1977                                             "constructing info for partially restored package",          
1978                                             true);                                                       
1979                                     info = getRestoredItemInfo(c, titleIndex, intent);                   
1980                                     intent = getRestoredItemIntent(c, context, intent);                  
1981                                 } else if (itemType ==                                                   
1982                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {              
1983                                     info = getShortcutInfo(manager, intent, context, c, iconIndex,       
1984                                             titleIndex, mLabelCache);                                    
1985                                 } else {                                                                 
1986                                     info = getShortcutInfo(c, context, iconTypeIndex,                    
1987                                             iconPackageIndex, iconResourceIndex, iconIndex,              
1988                                             titleIndex);                                                 
1989                                                                                                          
1990                                     // App shortcuts that used to be automatically added to Launcher     
1991                                     // didn't always have the correct intent flags set, so do that       
1992                                     // here                                                              
1993                                     if (intent.getAction() != null &&                                    
1994                                         intent.getCategories() != null &&                                
1995                                         intent.getAction().equals(Intent.ACTION_MAIN) &&                 
1996                                         intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {     
1997                                         intent.addFlags(                                                 
1998                                             Intent.FLAG_ACTIVITY_NEW_TASK |                              
1999                                             Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                  
2000                                     }                                                                    
2001                                 }                                                                        
2002                                                                                                          
2003                                 if (info != null) {                                                      
2004                                     info.id = id;                                                        
2005                                     info.intent = intent;                                                
2006                                     container = c.getInt(containerIndex);                                
2007                                     info.container = container;                                          
2008                                     info.screenId = c.getInt(screenIndex);                               
2009                                     info.cellX = c.getInt(cellXIndex);                                   
2010                                     info.cellY = c.getInt(cellYIndex);                                   
2011                                     info.spanX = 1;                                                      
2012                                     info.spanY = 1;                                                      
2013                                                                                                          
2014                                     // check & update map of what's occupied                             
2015                                     deleteOnInvalidPlacement.set(false);                                 
2016                                     if (!checkItemPlacement(occupied, info, deleteOnInvalidPlacement)) { 
2017                                         if (deleteOnInvalidPlacement.get()) {                            
2018                                             itemsToRemove.add(id);                                       
2019                                         }                                                                
2020                                         break;                                                           
2021                                     }                                                                    
2022                                                                                                          
2023                                     switch (container) {                                                 
2024                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2025                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2026                                         sBgWorkspaceItems.add(info);                                     
2027                                         break;                                                           
2028                                     default:                                                             
2029                                         // Item is in a user folder                                      
2030                                         FolderInfo folderInfo =                                          
2031                                                 findOrMakeFolder(sBgFolders, container);                 
2032                                         folderInfo.add(info);                                            
2033                                         break;                                                           
2034                                     }                                                                    
2035                                     sBgItemsIdMap.put(info.id, info);                                    
2036                                                                                                          
2037                                     // now that we've loaded everthing re-save it with the               
2038                                     // icon in case it disappears somehow.                               
2039                                     queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);            
2040                                 } else {                                                                 
2041                                     throw new RuntimeException("Unexpected null ShortcutInfo");          
2042                                 }                                                                        
2043                                 break;                                                                   
2044                                                                                                          
2045                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
2046                                 id = c.getLong(idIndex);                                                 
2047                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                
2048                                                                                                          
2049                                 folderInfo.title = c.getString(titleIndex);                              
2050                                 folderInfo.id = id;                                                      
2051                                 container = c.getInt(containerIndex);                                    
2052                                 folderInfo.container = container;                                        
2053                                 folderInfo.screenId = c.getInt(screenIndex);                             
2054                                 folderInfo.cellX = c.getInt(cellXIndex);                                 
2055                                 folderInfo.cellY = c.getInt(cellYIndex);                                 
2056                                 folderInfo.spanX = 1;                                                    
2057                                 folderInfo.spanY = 1;                                                    
2058                                                                                                          
2059                                 // check & update map of what's occupied                                 
2060                                 deleteOnInvalidPlacement.set(false);                                     
2061                                 if (!checkItemPlacement(occupied, folderInfo,                            
2062                                         deleteOnInvalidPlacement)) {                                     
2063                                     if (deleteOnInvalidPlacement.get()) {                                
2064                                         itemsToRemove.add(id);                                           
2065                                     }                                                                    
2066                                     break;                                                               
2067                                 }                                                                        
2068                                                                                                          
2069                                 switch (container) {                                                     
2070                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2071                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2072                                         sBgWorkspaceItems.add(folderInfo);                               
2073                                         break;                                                           
2074                                 }                                                                        
2075                                                                                                          
2076                                 if (restored) {                                                          
2077                                     // no special handling required for restored folders                 
2078                                     restoredRows.add(id);                                                
2079                                 }                                                                        
2080                                                                                                          
2081                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);                            
2082                                 sBgFolders.put(folderInfo.id, folderInfo);                               
2083                                 break;                                                                   
2084                                                                                                          
2085                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
2086                                 // Read all Launcher-specific widget details                             
2087                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
2088                                 String savedProvider = c.getString(appWidgetProviderIndex);              
2089                                                                                                          
2090                                 id = c.getLong(idIndex);                                                 
2091                                                                                                          
2092                                 final AppWidgetProviderInfo provider =                                   
2093                                         widgets.getAppWidgetInfo(appWidgetId);                           
2094                                                                                                          
2095                                 if (!isSafeMode && (provider == null || provider.provider == null ||     
2096                                         provider.provider.getPackageName() == null)) {                   
2097                                     String log = "Deleting widget that isn't installed anymore: id="     
2098                                         + id + " appWidgetId=" + appWidgetId;                            
2099                                     Log.e(TAG, log);                                                     
2100                                     Launcher.addDumpLog(TAG, log, false);                                
2101                                     itemsToRemove.add(id);                                               
2102                                 } else {                                                                 
2103                                     appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,               
2104                                             provider.provider);                                          
2105                                     appWidgetInfo.id = id;                                               
2106                                     appWidgetInfo.screenId = c.getInt(screenIndex);                      
2107                                     appWidgetInfo.cellX = c.getInt(cellXIndex);                          
2108                                     appWidgetInfo.cellY = c.getInt(cellYIndex);                          
2109                                     appWidgetInfo.spanX = c.getInt(spanXIndex);                          
2110                                     appWidgetInfo.spanY = c.getInt(spanYIndex);                          
2111                                     int[] minSpan = Launcher.getMinSpanForWidget(context, provider);     
2112                                     appWidgetInfo.minSpanX = minSpan[0];                                 
2113                                     appWidgetInfo.minSpanY = minSpan[1];                                 
2114                                                                                                          
2115                                     container = c.getInt(containerIndex);                                
2116                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&     
2117                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {     
2118                                         Log.e(TAG, "Widget found where container != " +                  
2119                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");      
2120                                         continue;                                                        
2121                                     }                                                                    
2122                                                                                                          
2123                                     appWidgetInfo.container = c.getInt(containerIndex);                  
2124                                     // check & update map of what's occupied                             
2125                                     deleteOnInvalidPlacement.set(false);                                 
2126                                     if (!checkItemPlacement(occupied, appWidgetInfo,                     
2127                                             deleteOnInvalidPlacement)) {                                 
2128                                         if (deleteOnInvalidPlacement.get()) {                            
2129                                             itemsToRemove.add(id);                                       
2130                                         }                                                                
2131                                         break;                                                           
2132                                     }                                                                    
2133                                     String providerName = provider.provider.flattenToString();           
2134                                     if (!providerName.equals(savedProvider)) {                           
2135                                         ContentValues values = new ContentValues();                      
2136                                         values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,        
2137                                                 providerName);                                           
2138                                         String where = BaseColumns._ID + "= ?";                          
2139                                         String[] args = {Integer.toString(c.getInt(idIndex))};           
2140                                         contentResolver.update(contentUri, values, where, args);         
2141                                     }                                                                    
2142                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                  
2143                                     sBgAppWidgets.add(appWidgetInfo);                                    
2144                                 }                                                                        
2145                                 break;                                                                   
2146                             }                                                                            
2147                         } catch (Exception e) {                                                          
2148                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2149                         }                                                                                
2150                     }                                                                                    
2151                 } finally {                                                                              
2152                     if (c != null) {                                                                     
2153                         c.close();                                                                       
2154                     }                                                                                    
2155                 }                                                                                        
2156                                                                                                          
2157                 // Break early if we've stopped loading                                                  
2158                 if (mStopped) {                                                                          
2159                     clearSBgDataStructures();                                                            
2160                     return false;                                                                        
2161                 }                                                                                        
2162                                                                                                          
2163                 if (itemsToRemove.size() > 0) {                                                          
2164                     ContentProviderClient client = contentResolver.acquireContentProviderClient(         
2165                             LauncherSettings.Favorites.CONTENT_URI);                                     
2166                     // Remove dead items                                                                 
2167                     for (long id : itemsToRemove) {                                                      
2168                         if (DEBUG_LOADERS) {                                                             
2169                             Log.d(TAG, "Removed id = " + id);                                            
2170                         }                                                                                
2171                         // Don't notify content observers                                                
2172                         try {                                                                            
2173                             client.delete(LauncherSettings.Favorites.getContentUri(id, false),           
2174                                     null, null);                                                         
2175                         } catch (RemoteException e) {                                                    
2176                             Log.w(TAG, "Could not remove id = " + id);                                   
2177                         }                                                                                
2178                     }                                                                                    
2179                 }                                                                                        
2180                                                                                                          
2181                 if (restoredRows.size() > 0) {                                                           
2182                     ContentProviderClient updater = contentResolver.acquireContentProviderClient(        
2183                             LauncherSettings.Favorites.CONTENT_URI);                                     
2184                     // Update restored items that no longer require special handling                     
2185                     try {                                                                                
2186                         StringBuilder selectionBuilder = new StringBuilder();                            
2187                         selectionBuilder.append(LauncherSettings.Favorites._ID);                         
2188                         selectionBuilder.append(" IN (");                                                
2189                         selectionBuilder.append(TextUtils.join(", ", restoredRows));                     
2190                         selectionBuilder.append(")");                                                    
2191                         ContentValues values = new ContentValues();                                      
2192                         values.put(LauncherSettings.Favorites.RESTORED, 0);                              
2193                         updater.update(LauncherSettings.Favorites.CONTENT_URI,                           
2194                                 values, selectionBuilder.toString(), null);                              
2195                     } catch (RemoteException e) {                                                        
2196                         Log.w(TAG, "Could not update restored rows");                                    
2197                     }                                                                                    
2198                 }                                                                                        
2199                                                                                                          
2200                 if (loadedOldDb) {                                                                       
2201                     long maxScreenId = 0;                                                                
2202                     // If we're importing we use the old screen order.                                   
2203                     for (ItemInfo item: sBgItemsIdMap.values()) {                                        
2204                         long screenId = item.screenId;                                                   
2205                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&            
2206                                 !sBgWorkspaceScreens.contains(screenId)) {                               
2207                             sBgWorkspaceScreens.add(screenId);                                           
2208                             if (screenId > maxScreenId) {                                                
2209                                 maxScreenId = screenId;                                                  
2210                             }                                                                            
2211                         }                                                                                
2212                     }                                                                                    
2213                     Collections.sort(sBgWorkspaceScreens);                                               
2214                     // Log to disk                                                                       
2215                     Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);          
2216                     Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                      
2217                             TextUtils.join(", ", sBgWorkspaceScreens), true);                            
2218                                                                                                          
2219                     LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);               
2220                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2221                                                                                                          
2222                     // Update the max item id after we load an old db                                    
2223                     long maxItemId = 0;                                                                  
2224                     // If we're importing we use the old screen order.                                   
2225                     for (ItemInfo item: sBgItemsIdMap.values()) {                                        
2226                         maxItemId = Math.max(maxItemId, item.id);                                        
2227                     }                                                                                    
2228                     LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);                   
2229                 } else {                                                                                 
2230                     TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);            
2231                     for (Integer i : orderedScreens.keySet()) {                                          
2232                         sBgWorkspaceScreens.add(orderedScreens.get(i));                                  
2233                     }                                                                                    
2234                     // Log to disk                                                                       
2235                     Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                      
2236                             TextUtils.join(", ", sBgWorkspaceScreens), true);                            
2237                                                                                                          
2238                     // Remove any empty screens                                                          
2239                     ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);            
2240                     for (ItemInfo item: sBgItemsIdMap.values()) {                                        
2241                         long screenId = item.screenId;                                                   
2242                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&            
2243                                 unusedScreens.contains(screenId)) {                                      
2244                             unusedScreens.remove(screenId);                                              
2245                         }                                                                                
2246                     }                                                                                    
2247                                                                                                          
2248                     // If there are any empty screens remove them, and update.                           
2249                     if (unusedScreens.size() != 0) {                                                     
2250                         // Log to disk                                                                   
2251                         Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +        
2252                                 TextUtils.join(", ", unusedScreens), true);                              
2253                                                                                                          
2254                         sBgWorkspaceScreens.removeAll(unusedScreens);                                    
2255                         updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                        
2256                     }                                                                                    
2257                 }                                                                                        
2258                                                                                                          
2259                 if (DEBUG_LOADERS) {                                                                     
2260                     Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");          
2261                     Log.d(TAG, "workspace layout: ");                                                    
2262                     int nScreens = occupied.size();                                                      
2263                     for (int y = 0; y < countY; y++) {                                                   
2264                         String line = "";                                                                
2265                                                                                                          
2266                         Iterator<Long> iter = occupied.keySet().iterator();                              
2267                         while (iter.hasNext()) {                                                         
2268                             long screenId = iter.next();                                                 
2269                             if (screenId > 0) {                                                          
2270                                 line += " | ";                                                           
2271                             }                                                                            
2272                             for (int x = 0; x < countX; x++) {                                           
2273                                 line += ((occupied.get(screenId)[x][y] != null) ? "#" : ".");            
2274                             }                                                                            
2275                         }                                                                                
2276                         Log.d(TAG, "[ " + line + " ]");                                                  
2277                     }                                                                                    
2278                 }                                                                                        
2279             }                                                                                            
2280             return loadedOldDb;                                                                          
2281         }                                                                                                
2282                                                                                                          
2283         /** Filters the set of items who are directly or indirectly (via another container) on the       
2284          * specified screen. */                                                                          
2285         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2286                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2287                 ArrayList<ItemInfo> currentScreenItems,                                                  
2288                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2289             // Purge any null ItemInfos                                                                  
2290             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2291             while (iter.hasNext()) {                                                                     
2292                 ItemInfo i = iter.next();                                                                
2293                 if (i == null) {                                                                         
2294                     iter.remove();                                                                       
2295                 }                                                                                        
2296             }                                                                                            
2297                                                                                                          
2298             // Order the set of items by their containers first, this allows use to walk through the     
2299             // list sequentially, build up a list of containers that are in the specified screen,        
2300             // as well as all items in those containers.                                                 
2301             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2302             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2303                 @Override                                                                                
2304                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2305                     return (int) (lhs.container - rhs.container);                                        
2306                 }                                                                                        
2307             });                                                                                          
2308             for (ItemInfo info : allWorkspaceItems) {                                                    
2309                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2310                     if (info.screenId == currentScreenId) {                                              
2311                         currentScreenItems.add(info);                                                    
2312                         itemsOnScreen.add(info.id);                                                      
2313                     } else {                                                                             
2314                         otherScreenItems.add(info);                                                      
2315                     }                                                                                    
2316                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2317                     currentScreenItems.add(info);                                                        
2318                     itemsOnScreen.add(info.id);                                                          
2319                 } else {                                                                                 
2320                     if (itemsOnScreen.contains(info.container)) {                                        
2321                         currentScreenItems.add(info);                                                    
2322                         itemsOnScreen.add(info.id);                                                      
2323                     } else {                                                                             
2324                         otherScreenItems.add(info);                                                      
2325                     }                                                                                    
2326                 }                                                                                        
2327             }                                                                                            
2328         }                                                                                                
2329                                                                                                          
2330         /** Filters the set of widgets which are on the specified screen. */                             
2331         private void filterCurrentAppWidgets(long currentScreenId,                                       
2332                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2333                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2334                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2335                                                                                                          
2336             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2337                 if (widget == null) continue;                                                            
2338                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2339                         widget.screenId == currentScreenId) {                                            
2340                     currentScreenWidgets.add(widget);                                                    
2341                 } else {                                                                                 
2342                     otherScreenWidgets.add(widget);                                                      
2343                 }                                                                                        
2344             }                                                                                            
2345         }                                                                                                
2346                                                                                                          
2347         /** Filters the set of folders which are on the specified screen. */                             
2348         private void filterCurrentFolders(long currentScreenId,                                          
2349                 HashMap<Long, ItemInfo> itemsIdMap,                                                      
2350                 HashMap<Long, FolderInfo> folders,                                                       
2351                 HashMap<Long, FolderInfo> currentScreenFolders,                                          
2352                 HashMap<Long, FolderInfo> otherScreenFolders) {                                          
2353                                                                                                          
2354             for (long id : folders.keySet()) {                                                           
2355                 ItemInfo info = itemsIdMap.get(id);                                                      
2356                 FolderInfo folder = folders.get(id);                                                     
2357                 if (info == null || folder == null) continue;                                            
2358                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2359                         info.screenId == currentScreenId) {                                              
2360                     currentScreenFolders.put(id, folder);                                                
2361                 } else {                                                                                 
2362                     otherScreenFolders.put(id, folder);                                                  
2363                 }                                                                                        
2364             }                                                                                            
2365         }                                                                                                
2366                                                                                                          
2367         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2368          * right) */                                                                                     
2369         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2370             final LauncherAppState app = LauncherAppState.getInstance();                                 
2371             final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                          
2372             // XXX: review this                                                                          
2373             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2374                 @Override                                                                                
2375                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2376                     int cellCountX = (int) grid.numColumns;                                              
2377                     int cellCountY = (int) grid.numRows;                                                 
2378                     int screenOffset = cellCountX * cellCountY;                                          
2379                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2380                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2381                             lhs.cellY * cellCountX + lhs.cellX);                                         
2382                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2383                             rhs.cellY * cellCountX + rhs.cellX);                                         
2384                     return (int) (lr - rr);                                                              
2385                 }                                                                                        
2386             });                                                                                          
2387         }                                                                                                
2388                                                                                                          
2389         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2390                 final ArrayList<Long> orderedScreens) {                                                  
2391             final Runnable r = new Runnable() {                                                          
2392                 @Override                                                                                
2393                 public void run() {                                                                      
2394                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2395                     if (callbacks != null) {                                                             
2396                         callbacks.bindScreens(orderedScreens);                                           
2397                     }                                                                                    
2398                 }                                                                                        
2399             };                                                                                           
2400             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2401         }                                                                                                
2402                                                                                                          
2403         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2404                 final ArrayList<ItemInfo> workspaceItems,                                                
2405                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2406                 final HashMap<Long, FolderInfo> folders,                                                 
2407                 ArrayList<Runnable> deferredBindRunnables) {                                             
2408                                                                                                          
2409             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2410                                                                                                          
2411             // Bind the workspace items                                                                  
2412             int N = workspaceItems.size();                                                               
2413             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2414                 final int start = i;                                                                     
2415                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2416                 final Runnable r = new Runnable() {                                                      
2417                     @Override                                                                            
2418                     public void run() {                                                                  
2419                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2420                         if (callbacks != null) {                                                         
2421                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2422                                     false);                                                              
2423                         }                                                                                
2424                     }                                                                                    
2425                 };                                                                                       
2426                 if (postOnMainThread) {                                                                  
2427                     deferredBindRunnables.add(r);                                                        
2428                 } else {                                                                                 
2429                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2430                 }                                                                                        
2431             }                                                                                            
2432                                                                                                          
2433             // Bind the folders                                                                          
2434             if (!folders.isEmpty()) {                                                                    
2435                 final Runnable r = new Runnable() {                                                      
2436                     public void run() {                                                                  
2437                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2438                         if (callbacks != null) {                                                         
2439                             callbacks.bindFolders(folders);                                              
2440                         }                                                                                
2441                     }                                                                                    
2442                 };                                                                                       
2443                 if (postOnMainThread) {                                                                  
2444                     deferredBindRunnables.add(r);                                                        
2445                 } else {                                                                                 
2446                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2447                 }                                                                                        
2448             }                                                                                            
2449                                                                                                          
2450             // Bind the widgets, one at a time                                                           
2451             N = appWidgets.size();                                                                       
2452             for (int i = 0; i < N; i++) {                                                                
2453                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2454                 final Runnable r = new Runnable() {                                                      
2455                     public void run() {                                                                  
2456                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2457                         if (callbacks != null) {                                                         
2458                             callbacks.bindAppWidget(widget);                                             
2459                         }                                                                                
2460                     }                                                                                    
2461                 };                                                                                       
2462                 if (postOnMainThread) {                                                                  
2463                     deferredBindRunnables.add(r);                                                        
2464                 } else {                                                                                 
2465                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2466                 }                                                                                        
2467             }                                                                                            
2468         }                                                                                                
2469                                                                                                          
2470         /**                                                                                              
2471          * Binds all loaded data to actual views on the main thread.                                     
2472          */                                                                                              
2473         private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {               
2474             final long t = SystemClock.uptimeMillis();                                                   
2475             Runnable r;                                                                                  
2476                                                                                                          
2477             // Don't use these two variables in any of the callback runnables.                           
2478             // Otherwise we hold a reference to them.                                                    
2479             final Callbacks oldCallbacks = mCallbacks.get();                                             
2480             if (oldCallbacks == null) {                                                                  
2481                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2482                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2483                 return;                                                                                  
2484             }                                                                                            
2485                                                                                                          
2486             // Save a copy of all the bg-thread collections                                              
2487             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2488             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2489                     new ArrayList<LauncherAppWidgetInfo>();                                              
2490             HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                         
2491             HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                          
2492             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2493             synchronized (sBgLock) {                                                                     
2494                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2495                 appWidgets.addAll(sBgAppWidgets);                                                        
2496                 folders.putAll(sBgFolders);                                                              
2497                 itemsIdMap.putAll(sBgItemsIdMap);                                                        
2498                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2499             }                                                                                            
2500                                                                                                          
2501             final boolean isLoadingSynchronously =                                                       
2502                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2503             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2504                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2505             if (currScreen >= orderedScreenIds.size()) {                                                 
2506                 // There may be no workspace screens (just hotseat items and an empty page).             
2507                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2508             }                                                                                            
2509             final int currentScreen = currScreen;                                                        
2510             final long currentScreenId = currentScreen < 0                                               
2511                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2512                                                                                                          
2513             // Load all the items that are on the current page first (and in the process, unbind         
2514             // all the existing workspace items before we call startBinding() below.                     
2515             unbindWorkspaceItemsOnMainThread();                                                          
2516                                                                                                          
2517             // Separate the items that are on the current screen, and all the other remaining items      
2518             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2519             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2520             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2521                     new ArrayList<LauncherAppWidgetInfo>();                                              
2522             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2523                     new ArrayList<LauncherAppWidgetInfo>();                                              
2524             HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                  
2525             HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                    
2526                                                                                                          
2527             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2528                     otherWorkspaceItems);                                                                
2529             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2530                     otherAppWidgets);                                                                    
2531             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2532                     otherFolders);                                                                       
2533             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2534             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2535                                                                                                          
2536             // Tell the workspace that we're about to start binding items                                
2537             r = new Runnable() {                                                                         
2538                 public void run() {                                                                      
2539                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2540                     if (callbacks != null) {                                                             
2541                         callbacks.startBinding();                                                        
2542                     }                                                                                    
2543                 }                                                                                        
2544             };                                                                                           
2545             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2546                                                                                                          
2547             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2548                                                                                                          
2549             // Load items on the current page                                                            
2550             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2551                     currentFolders, null);                                                               
2552             if (isLoadingSynchronously) {                                                                
2553                 r = new Runnable() {                                                                     
2554                     public void run() {                                                                  
2555                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2556                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2557                             callbacks.onPageBoundSynchronously(currentScreen);                           
2558                         }                                                                                
2559                     }                                                                                    
2560                 };                                                                                       
2561                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2562             }                                                                                            
2563                                                                                                          
2564             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2565             // work until after the first render)                                                        
2566             mDeferredBindRunnables.clear();                                                              
2567             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2568                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2569                                                                                                          
2570             // Tell the workspace that we're done binding items                                          
2571             r = new Runnable() {                                                                         
2572                 public void run() {                                                                      
2573                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2574                     if (callbacks != null) {                                                             
2575                         callbacks.finishBindingItems(isUpgradePath);                                     
2576                     }                                                                                    
2577                                                                                                          
2578                     // If we're profiling, ensure this is the last thing in the queue.                   
2579                     if (DEBUG_LOADERS) {                                                                 
2580                         Log.d(TAG, "bound workspace in "                                                 
2581                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2582                     }                                                                                    
2583                                                                                                          
2584                     mIsLoadingAndBindingWorkspace = false;                                               
2585                 }                                                                                        
2586             };                                                                                           
2587             if (isLoadingSynchronously) {                                                                
2588                 mDeferredBindRunnables.add(r);                                                           
2589             } else {                                                                                     
2590                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2591             }                                                                                            
2592         }                                                                                                
2593                                                                                                          
2594         private void loadAndBindAllApps() {                                                              
2595             if (DEBUG_LOADERS) {                                                                         
2596                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2597             }                                                                                            
2598             if (!mAllAppsLoaded) {                                                                       
2599                 loadAllApps();                                                                           
2600                 synchronized (LoaderTask.this) {                                                         
2601                     if (mStopped) {                                                                      
2602                         return;                                                                          
2603                     }                                                                                    
2604                     mAllAppsLoaded = true;                                                               
2605                 }                                                                                        
2606             } else {                                                                                     
2607                 onlyBindAllApps();                                                                       
2608             }                                                                                            
2609         }                                                                                                
2610                                                                                                          
2611         private void onlyBindAllApps() {                                                                 
2612             final Callbacks oldCallbacks = mCallbacks.get();                                             
2613             if (oldCallbacks == null) {                                                                  
2614                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2615                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2616                 return;                                                                                  
2617             }                                                                                            
2618                                                                                                          
2619             // shallow copy                                                                              
2620             @SuppressWarnings("unchecked")                                                               
2621             final ArrayList<AppInfo> list                                                                
2622                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2623             Runnable r = new Runnable() {                                                                
2624                 public void run() {                                                                      
2625                     final long t = SystemClock.uptimeMillis();                                           
2626                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2627                     if (callbacks != null) {                                                             
2628                         callbacks.bindAllApplications(list);                                             
2629                     }                                                                                    
2630                     if (DEBUG_LOADERS) {                                                                 
2631                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2632                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2633                     }                                                                                    
2634                 }                                                                                        
2635             };                                                                                           
2636             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2637             if (isRunningOnMainThread) {                                                                 
2638                 r.run();                                                                                 
2639             } else {                                                                                     
2640                 mHandler.post(r);                                                                        
2641             }                                                                                            
2642         }                                                                                                
2643                                                                                                          
2644         private void loadAllApps() {                                                                     
2645             final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2646                                                                                                          
2647             final Callbacks oldCallbacks = mCallbacks.get();                                             
2648             if (oldCallbacks == null) {                                                                  
2649                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2650                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2651                 return;                                                                                  
2652             }                                                                                            
2653                                                                                                          
2654             final PackageManager packageManager = mContext.getPackageManager();                          
2655             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                              
2656             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                            
2657                                                                                                          
2658             // Clear the list of apps                                                                    
2659             mBgAllAppsList.clear();                                                                      
2660                                                                                                          
2661             // Query for the set of apps                                                                 
2662             final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                         
2663             List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);                
2664             if (DEBUG_LOADERS) {                                                                         
2665                 Log.d(TAG, "queryIntentActivities took "                                                 
2666                         + (SystemClock.uptimeMillis()-qiaTime) + "ms");                                  
2667                 Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");                        
2668             }                                                                                            
2669             // Fail if we don't have any apps                                                            
2670             if (apps == null || apps.isEmpty()) {                                                        
2671                 return;                                                                                  
2672             }                                                                                            
2673             // Sort the applications by name                                                             
2674             final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2675             Collections.sort(apps,                                                                       
2676                     new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));              
2677             if (DEBUG_LOADERS) {                                                                         
2678                 Log.d(TAG, "sort took "                                                                  
2679                         + (SystemClock.uptimeMillis()-sortTime) + "ms");                                 
2680             }                                                                                            
2681                                                                                                          
2682             // Create the ApplicationInfos                                                               
2683             for (int i = 0; i < apps.size(); i++) {                                                      
2684                 ResolveInfo app = apps.get(i);                                                           
2685                 // This builds the icon bitmaps.                                                         
2686                 mBgAllAppsList.add(new AppInfo(packageManager, app,                                      
2687                         mIconCache, mLabelCache));                                                       
2688             }                                                                                            
2689                                                                                                          
2690             // Huh? Shouldn't this be inside the Runnable below?                                         
2691             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2692             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2693                                                                                                          
2694             // Post callback on main thread                                                              
2695             mHandler.post(new Runnable() {                                                               
2696                 public void run() {                                                                      
2697                     final long bindTime = SystemClock.uptimeMillis();                                    
2698                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2699                     if (callbacks != null) {                                                             
2700                         callbacks.bindAllApplications(added);                                            
2701                         if (DEBUG_LOADERS) {                                                             
2702                             Log.d(TAG, "bound " + added.size() + " apps in "                             
2703                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");                       
2704                         }                                                                                
2705                     } else {                                                                             
2706                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2707                     }                                                                                    
2708                 }                                                                                        
2709             });                                                                                          
2710                                                                                                          
2711             if (DEBUG_LOADERS) {                                                                         
2712                 Log.d(TAG, "Icons processed in "                                                         
2713                         + (SystemClock.uptimeMillis() - loadTime) + "ms");                               
2714             }                                                                                            
2715         }                                                                                                
2716                                                                                                          
2717         public void dumpState() {                                                                        
2718             synchronized (sBgLock) {                                                                     
2719                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2720                 Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                  
2721                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2722                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2723                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2724             }                                                                                            
2725         }                                                                                                
2726     }                                                                                                    
2727                                                                                                          
2728     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2729         sWorker.post(task);                                                                              
2730     }                                                                                                    
2731                                                                                                          
2732     private class PackageUpdatedTask implements Runnable {                                               
2733         int mOp;                                                                                         
2734         String[] mPackages;                                                                              
2735                                                                                                          
2736         public static final int OP_NONE = 0;                                                             
2737         public static final int OP_ADD = 1;                                                              
2738         public static final int OP_UPDATE = 2;                                                           
2739         public static final int OP_REMOVE = 3; // uninstlled                                             
2740         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2741                                                                                                          
2742                                                                                                          
2743         public PackageUpdatedTask(int op, String[] packages) {                                           
2744             mOp = op;                                                                                    
2745             mPackages = packages;                                                                        
2746         }                                                                                                
2747                                                                                                          
2748         public void run() {                                                                              
2749             final Context context = mApp.getContext();                                                   
2750                                                                                                          
2751             final String[] packages = mPackages;                                                         
2752             final int N = packages.length;                                                               
2753             switch (mOp) {                                                                               
2754                 case OP_ADD:                                                                             
2755                     for (int i=0; i<N; i++) {                                                            
2756                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);         
2757                         mBgAllAppsList.addPackage(context, packages[i]);                                 
2758                     }                                                                                    
2759                     break;                                                                               
2760                 case OP_UPDATE:                                                                          
2761                     for (int i=0; i<N; i++) {                                                            
2762                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);      
2763                         mBgAllAppsList.updatePackage(context, packages[i]);                              
2764                         WidgetPreviewLoader.removePackageFromDb(                                         
2765                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
2766                     }                                                                                    
2767                     break;                                                                               
2768                 case OP_REMOVE:                                                                          
2769                 case OP_UNAVAILABLE:                                                                     
2770                     for (int i=0; i<N; i++) {                                                            
2771                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
2772                         mBgAllAppsList.removePackage(packages[i]);                                       
2773                         WidgetPreviewLoader.removePackageFromDb(                                         
2774                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
2775                     }                                                                                    
2776                     break;                                                                               
2777             }                                                                                            
2778                                                                                                          
2779             ArrayList<AppInfo> added = null;                                                             
2780             ArrayList<AppInfo> modified = null;                                                          
2781             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
2782                                                                                                          
2783             if (mBgAllAppsList.added.size() > 0) {                                                       
2784                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
2785                 mBgAllAppsList.added.clear();                                                            
2786             }                                                                                            
2787             if (mBgAllAppsList.modified.size() > 0) {                                                    
2788                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
2789                 mBgAllAppsList.modified.clear();                                                         
2790             }                                                                                            
2791             if (mBgAllAppsList.removed.size() > 0) {                                                     
2792                 removedApps.addAll(mBgAllAppsList.removed);                                              
2793                 mBgAllAppsList.removed.clear();                                                          
2794             }                                                                                            
2795                                                                                                          
2796             final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                    
2797             if (callbacks == null) {                                                                     
2798                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
2799                 return;                                                                                  
2800             }                                                                                            
2801                                                                                                          
2802             if (added != null) {                                                                         
2803                 // Ensure that we add all the workspace applications to the db                           
2804                 Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                             
2805                 if (!LauncherAppState.isDisableAllApps()) {                                              
2806                     addAndBindAddedApps(context, new ArrayList<ItemInfo>(), cb, added);                  
2807                 } else {                                                                                 
2808                     final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);               
2809                     addAndBindAddedApps(context, addedInfos, cb, added);                                 
2810                 }                                                                                        
2811             }                                                                                            
2812             if (modified != null) {                                                                      
2813                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
2814                                                                                                          
2815                 // Update the launcher db to reflect the changes                                         
2816                 for (AppInfo a : modifiedFinal) {                                                        
2817                     ArrayList<ItemInfo> infos =                                                          
2818                             getItemInfoForComponentName(a.componentName);                                
2819                     for (ItemInfo i : infos) {                                                           
2820                         if (isShortcutInfoUpdateable(i)) {                                               
2821                             ShortcutInfo info = (ShortcutInfo) i;                                        
2822                             info.title = a.title.toString();                                             
2823                             updateItemInDatabase(context, info);                                         
2824                         }                                                                                
2825                     }                                                                                    
2826                 }                                                                                        
2827                                                                                                          
2828                 mHandler.post(new Runnable() {                                                           
2829                     public void run() {                                                                  
2830                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
2831                         if (callbacks == cb && cb != null) {                                             
2832                             callbacks.bindAppsUpdated(modifiedFinal);                                    
2833                         }                                                                                
2834                     }                                                                                    
2835                 });                                                                                      
2836             }                                                                                            
2837                                                                                                          
2838             final ArrayList<String> removedPackageNames =                                                
2839                     new ArrayList<String>();                                                             
2840             if (mOp == OP_REMOVE) {                                                                      
2841                 // Mark all packages in the broadcast to be removed                                      
2842                 removedPackageNames.addAll(Arrays.asList(packages));                                     
2843             } else if (mOp == OP_UPDATE) {                                                               
2844                 // Mark disabled packages in the broadcast to be removed                                 
2845                 final PackageManager pm = context.getPackageManager();                                   
2846                 for (int i=0; i<N; i++) {                                                                
2847                     if (isPackageDisabled(pm, packages[i])) {                                            
2848                         removedPackageNames.add(packages[i]);                                            
2849                     }                                                                                    
2850                 }                                                                                        
2851             }                                                                                            
2852             // Remove all the components associated with this package                                    
2853             for (String pn : removedPackageNames) {                                                      
2854                 ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);                               
2855                 for (ItemInfo i : infos) {                                                               
2856                     deleteItemFromDatabase(context, i);                                                  
2857                 }                                                                                        
2858             }                                                                                            
2859             // Remove all the specific components                                                        
2860             for (AppInfo a : removedApps) {                                                              
2861                 ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);                
2862                 for (ItemInfo i : infos) {                                                               
2863                     deleteItemFromDatabase(context, i);                                                  
2864                 }                                                                                        
2865             }                                                                                            
2866             if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                              
2867                 // Remove any queued items from the install queue                                        
2868                 String spKey = LauncherAppState.getSharedPreferencesKey();                               
2869                 SharedPreferences sp =                                                                   
2870                         context.getSharedPreferences(spKey, Context.MODE_PRIVATE);                       
2871                 InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames);                 
2872                 // Call the components-removed callback                                                  
2873                 mHandler.post(new Runnable() {                                                           
2874                     public void run() {                                                                  
2875                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
2876                         if (callbacks == cb && cb != null) {                                             
2877                             callbacks.bindComponentsRemoved(removedPackageNames, removedApps);           
2878                         }                                                                                
2879                     }                                                                                    
2880                 });                                                                                      
2881             }                                                                                            
2882                                                                                                          
2883             final ArrayList<Object> widgetsAndShortcuts =                                                
2884                 getSortedWidgetsAndShortcuts(context);                                                   
2885             mHandler.post(new Runnable() {                                                               
2886                 @Override                                                                                
2887                 public void run() {                                                                      
2888                     Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                         
2889                     if (callbacks == cb && cb != null) {                                                 
2890                         callbacks.bindPackagesUpdated(widgetsAndShortcuts);                              
2891                     }                                                                                    
2892                 }                                                                                        
2893             });                                                                                          
2894                                                                                                          
2895             // Write all the logs to disk                                                                
2896             mHandler.post(new Runnable() {                                                               
2897                 public void run() {                                                                      
2898                     Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                         
2899                     if (callbacks == cb && cb != null) {                                                 
2900                         callbacks.dumpLogsToLocalData();                                                 
2901                     }                                                                                    
2902                 }                                                                                        
2903             });                                                                                          
2904         }                                                                                                
2905     }                                                                                                    
2906                                                                                                          
2907     // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                     
2908     public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                      
2909         PackageManager packageManager = context.getPackageManager();                                     
2910         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
2911         widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders());       
2912         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
2913         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
2914         Collections.sort(widgetsAndShortcuts,                                                            
2915             new LauncherModel.WidgetAndShortcutNameComparator(packageManager));                          
2916         return widgetsAndShortcuts;                                                                      
2917     }                                                                                                    
2918                                                                                                          
2919     private static boolean isPackageDisabled(PackageManager pm, String packageName) {                    
2920         try {                                                                                            
2921             PackageInfo pi = pm.getPackageInfo(packageName, 0);                                          
2922             return !pi.applicationInfo.enabled;                                                          
2923         } catch (NameNotFoundException e) {                                                              
2924             // Fall through                                                                              
2925         }                                                                                                
2926         return false;                                                                                    
2927     }                                                                                                    
2928                                                                                                          
2929     public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) {                 
2930         if (cn == null) {                                                                                
2931             return false;                                                                                
2932         }                                                                                                
2933         if (isPackageDisabled(pm, cn.getPackageName())) {                                                
2934             return false;                                                                                
2935         }                                                                                                
2936                                                                                                          
2937         try {                                                                                            
2938             // Check the activity                                                                        
2939             PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0);                                  
2940             return (pm.getActivityInfo(cn, 0) != null);                                                  
2941         } catch (NameNotFoundException e) {                                                              
2942             return false;                                                                                
2943         }                                                                                                
2944     }                                                                                                    
2945                                                                                                          
2946     /**                                                                                                  
2947      * Make an ShortcutInfo object for a restored application or shortcut item that points               
2948      * to a package that is not yet installed on the system.                                             
2949      */                                                                                                  
2950     public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) {              
2951         final ShortcutInfo info = new ShortcutInfo();                                                    
2952         info.usingFallbackIcon = true;                                                                   
2953         info.setIcon(getFallbackIcon());                                                                 
2954         if (cursor != null) {                                                                            
2955             info.title =  cursor.getString(titleIndex);                                                  
2956         } else {                                                                                         
2957             info.title = "";                                                                             
2958         }                                                                                                
2959         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
2960         info.restoredIntent = intent;                                                                    
2961         return info;                                                                                     
2962     }                                                                                                    
2963                                                                                                          
2964     /**                                                                                                  
2965      * Make an Intent object for a restored application or shortcut item that points                     
2966      * to the market page for the item.                                                                  
2967      */                                                                                                  
2968     private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                     
2969         final boolean debug = false;                                                                     
2970         ComponentName componentName = intent.getComponent();                                             
2971         Intent marketIntent = new Intent(Intent.ACTION_VIEW);                                            
2972         Uri marketUri = new Uri.Builder()                                                                
2973                 .scheme("market")                                                                        
2974                 .authority("details")                                                                    
2975                 .appendQueryParameter("id", componentName.getPackageName())                              
2976                 .build();                                                                                
2977         if (debug) Log.d(TAG, "manufactured intent uri: " + marketUri.toString());                       
2978         marketIntent.setData(marketUri);                                                                 
2979         return marketIntent;                                                                             
2980     }                                                                                                    
2981                                                                                                          
2982     /**                                                                                                  
2983      * This is called from the code that adds shortcuts from the intent receiver.  This                  
2984      * doesn't have a Cursor, but                                                                        
2985      */                                                                                                  
2986     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {        
2987         return getShortcutInfo(manager, intent, context, null, -1, -1, null);                            
2988     }                                                                                                    
2989                                                                                                          
2990     /**                                                                                                  
2991      * Make an ShortcutInfo object for a shortcut that is an application.                                
2992      *                                                                                                   
2993      * If c is not null, then it will be used to fill in missing data like the title and icon.           
2994      */                                                                                                  
2995     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,          
2996             Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {         
2997         ComponentName componentName = intent.getComponent();                                             
2998         final ShortcutInfo info = new ShortcutInfo();                                                    
2999         if (componentName != null && !isValidPackageComponent(manager, componentName)) {                 
3000             Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName);                    
3001             return null;                                                                                 
3002         } else {                                                                                         
3003             try {                                                                                        
3004                 PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);              
3005                 info.initFlagsAndFirstInstallTime(pi);                                                   
3006             } catch (NameNotFoundException e) {                                                          
3007                 Log.d(TAG, "getPackInfo failed for package " +                                           
3008                         componentName.getPackageName());                                                 
3009             }                                                                                            
3010         }                                                                                                
3011                                                                                                          
3012         // TODO: See if the PackageManager knows about this case.  If it doesn't                         
3013         // then return null & delete this.                                                               
3014                                                                                                          
3015         // the resource -- This may implicitly give us back the fallback icon,                           
3016         // but don't worry about that.  All we're doing with usingFallbackIcon is                        
3017         // to avoid saving lots of copies of that in the database, and most apps                         
3018         // have icons anyway.                                                                            
3019                                                                                                          
3020         // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and      
3021         // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info     
3022         // via resolveActivity().                                                                        
3023         Bitmap icon = null;                                                                              
3024         ResolveInfo resolveInfo = null;                                                                  
3025         ComponentName oldComponent = intent.getComponent();                                              
3026         Intent newIntent = new Intent(intent.getAction(), null);                                         
3027         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3028         newIntent.setPackage(oldComponent.getPackageName());                                             
3029         List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);                           
3030         for (ResolveInfo i : infos) {                                                                    
3031             ComponentName cn = new ComponentName(i.activityInfo.packageName,                             
3032                     i.activityInfo.name);                                                                
3033             if (cn.equals(oldComponent)) {                                                               
3034                 resolveInfo = i;                                                                         
3035             }                                                                                            
3036         }                                                                                                
3037         if (resolveInfo == null) {                                                                       
3038             resolveInfo = manager.resolveActivity(intent, 0);                                            
3039         }                                                                                                
3040         if (resolveInfo != null) {                                                                       
3041             icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);                           
3042         }                                                                                                
3043         // the db                                                                                        
3044         if (icon == null) {                                                                              
3045             if (c != null) {                                                                             
3046                 icon = getIconFromCursor(c, iconIndex, context);                                         
3047             }                                                                                            
3048         }                                                                                                
3049         // the fallback icon                                                                             
3050         if (icon == null) {                                                                              
3051             icon = getFallbackIcon();                                                                    
3052             info.usingFallbackIcon = true;                                                               
3053         }                                                                                                
3054         info.setIcon(icon);                                                                              
3055                                                                                                          
3056         // from the resource                                                                             
3057         if (resolveInfo != null) {                                                                       
3058             ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);              
3059             if (labelCache != null && labelCache.containsKey(key)) {                                     
3060                 info.title = labelCache.get(key);                                                        
3061             } else {                                                                                     
3062                 info.title = resolveInfo.activityInfo.loadLabel(manager);                                
3063                 if (labelCache != null) {                                                                
3064                     labelCache.put(key, info.title);                                                     
3065                 }                                                                                        
3066             }                                                                                            
3067         }                                                                                                
3068         // from the db                                                                                   
3069         if (info.title == null) {                                                                        
3070             if (c != null) {                                                                             
3071                 info.title =  c.getString(titleIndex);                                                   
3072             }                                                                                            
3073         }                                                                                                
3074         // fall back to the class name of the activity                                                   
3075         if (info.title == null) {                                                                        
3076             info.title = componentName.getClassName();                                                   
3077         }                                                                                                
3078         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3079         return info;                                                                                     
3080     }                                                                                                    
3081                                                                                                          
3082     static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                               
3083             ItemInfoFilter f) {                                                                          
3084         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3085         for (ItemInfo i : infos) {                                                                       
3086             if (i instanceof ShortcutInfo) {                                                             
3087                 ShortcutInfo info = (ShortcutInfo) i;                                                    
3088                 ComponentName cn = info.intent.getComponent();                                           
3089                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3090                     filtered.add(info);                                                                  
3091                 }                                                                                        
3092             } else if (i instanceof FolderInfo) {                                                        
3093                 FolderInfo info = (FolderInfo) i;                                                        
3094                 for (ShortcutInfo s : info.contents) {                                                   
3095                     ComponentName cn = s.intent.getComponent();                                          
3096                     if (cn != null && f.filterItem(info, s, cn)) {                                       
3097                         filtered.add(s);                                                                 
3098                     }                                                                                    
3099                 }                                                                                        
3100             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3101                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
3102                 ComponentName cn = info.providerName;                                                    
3103                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3104                     filtered.add(info);                                                                  
3105                 }                                                                                        
3106             }                                                                                            
3107         }                                                                                                
3108         return new ArrayList<ItemInfo>(filtered);                                                        
3109     }                                                                                                    
3110                                                                                                          
3111     private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {                             
3112         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3113             @Override                                                                                    
3114             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3115                 return cn.getPackageName().equals(pn);                                                   
3116             }                                                                                            
3117         };                                                                                               
3118         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
3119     }                                                                                                    
3120                                                                                                          
3121     private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {                 
3122         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3123             @Override                                                                                    
3124             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3125                 return cn.equals(cname);                                                                 
3126             }                                                                                            
3127         };                                                                                               
3128         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
3129     }                                                                                                    
3130                                                                                                          
3131     public static boolean isShortcutInfoUpdateable(ItemInfo i) {                                         
3132         if (i instanceof ShortcutInfo) {                                                                 
3133             ShortcutInfo info = (ShortcutInfo) i;                                                        
3134             // We need to check for ACTION_MAIN otherwise getComponent() might                           
3135             // return null for some shortcuts (for instance, for shortcuts to                            
3136             // web pages.)                                                                               
3137             Intent intent = info.intent;                                                                 
3138             ComponentName name = intent.getComponent();                                                  
3139             if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&                     
3140                     Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {                     
3141                 return true;                                                                             
3142             }                                                                                            
3143             // placeholder shortcuts get special treatment, let them through too.                        
3144             if (info.getRestoredIntent() != null) {                                                      
3145                 return true;                                                                             
3146             }                                                                                            
3147         }                                                                                                
3148         return false;                                                                                    
3149     }                                                                                                    
3150                                                                                                          
3151     /**                                                                                                  
3152      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3153      */                                                                                                  
3154     private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                      
3155             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,               
3156             int titleIndex) {                                                                            
3157                                                                                                          
3158         Bitmap icon = null;                                                                              
3159         final ShortcutInfo info = new ShortcutInfo();                                                    
3160         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3161                                                                                                          
3162         // TODO: If there's an explicit component and we can't install that, delete it.                  
3163                                                                                                          
3164         info.title = c.getString(titleIndex);                                                            
3165                                                                                                          
3166         int iconType = c.getInt(iconTypeIndex);                                                          
3167         switch (iconType) {                                                                              
3168         case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                              
3169             String packageName = c.getString(iconPackageIndex);                                          
3170             String resourceName = c.getString(iconResourceIndex);                                        
3171             PackageManager packageManager = context.getPackageManager();                                 
3172             info.customIcon = false;                                                                     
3173             // the resource                                                                              
3174             try {                                                                                        
3175                 Resources resources = packageManager.getResourcesForApplication(packageName);            
3176                 if (resources != null) {                                                                 
3177                     final int id = resources.getIdentifier(resourceName, null, null);                    
3178                     icon = Utilities.createIconBitmap(                                                   
3179                             mIconCache.getFullResIcon(resources, id), context);                          
3180                 }                                                                                        
3181             } catch (Exception e) {                                                                      
3182                 // drop this.  we have other places to look for icons                                    
3183             }                                                                                            
3184             // the db                                                                                    
3185             if (icon == null) {                                                                          
3186                 icon = getIconFromCursor(c, iconIndex, context);                                         
3187             }                                                                                            
3188             // the fallback icon                                                                         
3189             if (icon == null) {                                                                          
3190                 icon = getFallbackIcon();                                                                
3191                 info.usingFallbackIcon = true;                                                           
3192             }                                                                                            
3193             break;                                                                                       
3194         case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                
3195             icon = getIconFromCursor(c, iconIndex, context);                                             
3196             if (icon == null) {                                                                          
3197                 icon = getFallbackIcon();                                                                
3198                 info.customIcon = false;                                                                 
3199                 info.usingFallbackIcon = true;                                                           
3200             } else {                                                                                     
3201                 info.customIcon = true;                                                                  
3202             }                                                                                            
3203             break;                                                                                       
3204         default:                                                                                         
3205             icon = getFallbackIcon();                                                                    
3206             info.usingFallbackIcon = true;                                                               
3207             info.customIcon = false;                                                                     
3208             break;                                                                                       
3209         }                                                                                                
3210         info.setIcon(icon);                                                                              
3211         return info;                                                                                     
3212     }                                                                                                    
3213                                                                                                          
3214     Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                 
3215         @SuppressWarnings("all") // suppress dead code warning                                           
3216         final boolean debug = false;                                                                     
3217         if (debug) {                                                                                     
3218             Log.d(TAG, "getIconFromCursor app="                                                          
3219                     + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));           
3220         }                                                                                                
3221         byte[] data = c.getBlob(iconIndex);                                                              
3222         try {                                                                                            
3223             return Utilities.createIconBitmap(                                                           
3224                     BitmapFactory.decodeByteArray(data, 0, data.length), context);                       
3225         } catch (Exception e) {                                                                          
3226             return null;                                                                                 
3227         }                                                                                                
3228     }                                                                                                    
3229                                                                                                          
3230     ShortcutInfo addShortcut(Context context, Intent data, long container, int screen,                   
3231             int cellX, int cellY, boolean notify) {                                                      
3232         final ShortcutInfo info = infoFromShortcutIntent(context, data, null);                           
3233         if (info == null) {                                                                              
3234             return null;                                                                                 
3235         }                                                                                                
3236         addItemToDatabase(context, info, container, screen, cellX, cellY, notify);                       
3237                                                                                                          
3238         return info;                                                                                     
3239     }                                                                                                    
3240                                                                                                          
3241     /**                                                                                                  
3242      * Attempts to find an AppWidgetProviderInfo that matches the given component.                       
3243      */                                                                                                  
3244     AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,                        
3245             ComponentName component) {                                                                   
3246         List<AppWidgetProviderInfo> widgets =                                                            
3247             AppWidgetManager.getInstance(context).getInstalledProviders();                               
3248         for (AppWidgetProviderInfo info : widgets) {                                                     
3249             if (info.provider.equals(component)) {                                                       
3250                 return info;                                                                             
3251             }                                                                                            
3252         }                                                                                                
3253         return null;                                                                                     
3254     }                                                                                                    
3255                                                                                                          
3256     /**                                                                                                  
3257      * Returns a list of all the widgets that can handle configuration with a particular mimeType.       
3258      */                                                                                                  
3259     List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {        
3260         final PackageManager packageManager = context.getPackageManager();                               
3261         final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =                         
3262             new ArrayList<WidgetMimeTypeHandlerData>();                                                  
3263                                                                                                          
3264         final Intent supportsIntent =                                                                    
3265             new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);                         
3266         supportsIntent.setType(mimeType);                                                                
3267                                                                                                          
3268         // Create a set of widget configuration components that we can test against                      
3269         final List<AppWidgetProviderInfo> widgets =                                                      
3270             AppWidgetManager.getInstance(context).getInstalledProviders();                               
3271         final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =             
3272             new HashMap<ComponentName, AppWidgetProviderInfo>();                                         
3273         for (AppWidgetProviderInfo info : widgets) {                                                     
3274             configurationComponentToWidget.put(info.configure, info);                                    
3275         }                                                                                                
3276                                                                                                          
3277         // Run through each of the intents that can handle this type of clip data, and cross             
3278         // reference them with the components that are actual configuration components                   
3279         final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,        
3280                 PackageManager.MATCH_DEFAULT_ONLY);                                                      
3281         for (ResolveInfo info : activities) {                                                            
3282             final ActivityInfo activityInfo = info.activityInfo;                                         
3283             final ComponentName infoComponent = new ComponentName(activityInfo.packageName,              
3284                     activityInfo.name);                                                                  
3285             if (configurationComponentToWidget.containsKey(infoComponent)) {                             
3286                 supportedConfigurationActivities.add(                                                    
3287                         new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,                        
3288                                 configurationComponentToWidget.get(infoComponent)));                     
3289             }                                                                                            
3290         }                                                                                                
3291         return supportedConfigurationActivities;                                                         
3292     }                                                                                                    
3293                                                                                                          
3294     ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {             
3295         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3296         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3297         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3298                                                                                                          
3299         if (intent == null) {                                                                            
3300             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3301             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3302             return null;                                                                                 
3303         }                                                                                                
3304                                                                                                          
3305         Bitmap icon = null;                                                                              
3306         boolean customIcon = false;                                                                      
3307         ShortcutIconResource iconResource = null;                                                        
3308                                                                                                          
3309         if (bitmap != null && bitmap instanceof Bitmap) {                                                
3310             icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);          
3311             customIcon = true;                                                                           
3312         } else {                                                                                         
3313             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3314             if (extra != null && extra instanceof ShortcutIconResource) {                                
3315                 try {                                                                                    
3316                     iconResource = (ShortcutIconResource) extra;                                         
3317                     final PackageManager packageManager = context.getPackageManager();                   
3318                     Resources resources = packageManager.getResourcesForApplication(                     
3319                             iconResource.packageName);                                                   
3320                     final int id = resources.getIdentifier(iconResource.resourceName, null, null);       
3321                     icon = Utilities.createIconBitmap(                                                   
3322                             mIconCache.getFullResIcon(resources, id), context);                          
3323                 } catch (Exception e) {                                                                  
3324                     Log.w(TAG, "Could not load shortcut icon: " + extra);                                
3325                 }                                                                                        
3326             }                                                                                            
3327         }                                                                                                
3328                                                                                                          
3329         final ShortcutInfo info = new ShortcutInfo();                                                    
3330                                                                                                          
3331         if (icon == null) {                                                                              
3332             if (fallbackIcon != null) {                                                                  
3333                 icon = fallbackIcon;                                                                     
3334             } else {                                                                                     
3335                 icon = getFallbackIcon();                                                                
3336                 info.usingFallbackIcon = true;                                                           
3337             }                                                                                            
3338         }                                                                                                
3339         info.setIcon(icon);                                                                              
3340                                                                                                          
3341         info.title = name;                                                                               
3342         info.intent = intent;                                                                            
3343         info.customIcon = customIcon;                                                                    
3344         info.iconResource = iconResource;                                                                
3345                                                                                                          
3346         return info;                                                                                     
3347     }                                                                                                    
3348                                                                                                          
3349     boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,             
3350             int iconIndex) {                                                                             
3351         // If apps can't be on SD, don't even bother.                                                    
3352         if (!mAppsCanBeOnRemoveableStorage) {                                                            
3353             return false;                                                                                
3354         }                                                                                                
3355         // If this icon doesn't have a custom icon, check to see                                         
3356         // what's stored in the DB, and if it doesn't match what                                         
3357         // we're going to show, store what we are going to show back                                     
3358         // into the DB.  We do this so when we're loading, if the                                        
3359         // package manager can't find an icon (for example because                                       
3360         // the app is on SD) then we can use that instead.                                               
3361         if (!info.customIcon && !info.usingFallbackIcon) {                                               
3362             cache.put(info, c.getBlob(iconIndex));                                                       
3363             return true;                                                                                 
3364         }                                                                                                
3365         return false;                                                                                    
3366     }                                                                                                    
3367     void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                              
3368         boolean needSave = false;                                                                        
3369         try {                                                                                            
3370             if (data != null) {                                                                          
3371                 Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                      
3372                 Bitmap loaded = info.getIcon(mIconCache);                                                
3373                 needSave = !saved.sameAs(loaded);                                                        
3374             } else {                                                                                     
3375                 needSave = true;                                                                         
3376             }                                                                                            
3377         } catch (Exception e) {                                                                          
3378             needSave = true;                                                                             
3379         }                                                                                                
3380         if (needSave) {                                                                                  
3381             Log.d(TAG, "going to save icon bitmap for info=" + info);                                    
3382             // This is slower than is ideal, but this only happens once                                  
3383             // or when the app is updated with a new icon.                                               
3384             updateItemInDatabase(context, info);                                                         
3385         }                                                                                                
3386     }                                                                                                    
3387                                                                                                          
3388     /**                                                                                                  
3389      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3390      * or make a new one.                                                                                
3391      */                                                                                                  
3392     private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {             
3393         // See if a placeholder was created for us already                                               
3394         FolderInfo folderInfo = folders.get(id);                                                         
3395         if (folderInfo == null) {                                                                        
3396             // No placeholder -- create a new instance                                                   
3397             folderInfo = new FolderInfo();                                                               
3398             folders.put(id, folderInfo);                                                                 
3399         }                                                                                                
3400         return folderInfo;                                                                               
3401     }                                                                                                    
3402                                                                                                          
3403     public static final Comparator<AppInfo> getAppNameComparator() {                                     
3404         final Collator collator = Collator.getInstance();                                                
3405         return new Comparator<AppInfo>() {                                                               
3406             public final int compare(AppInfo a, AppInfo b) {                                             
3407                 int result = collator.compare(a.title.toString().trim(),                                 
3408                         b.title.toString().trim());                                                      
3409                 if (result == 0) {                                                                       
3410                     result = a.componentName.compareTo(b.componentName);                                 
3411                 }                                                                                        
3412                 return result;                                                                           
3413             }                                                                                            
3414         };                                                                                               
3415     }                                                                                                    
3416     public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                  
3417             = new Comparator<AppInfo>() {                                                                
3418         public final int compare(AppInfo a, AppInfo b) {                                                 
3419             if (a.firstInstallTime < b.firstInstallTime) return 1;                                       
3420             if (a.firstInstallTime > b.firstInstallTime) return -1;                                      
3421             return 0;                                                                                    
3422         }                                                                                                
3423     };                                                                                                   
3424     public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() {                    
3425         final Collator collator = Collator.getInstance();                                                
3426         return new Comparator<AppWidgetProviderInfo>() {                                                 
3427             public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {                 
3428                 return collator.compare(a.label.toString().trim(), b.label.toString().trim());           
3429             }                                                                                            
3430         };                                                                                               
3431     }                                                                                                    
3432     static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                             
3433         if (info.activityInfo != null) {                                                                 
3434             return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);             
3435         } else {                                                                                         
3436             return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);               
3437         }                                                                                                
3438     }                                                                                                    
3439     public static class ShortcutNameComparator implements Comparator<ResolveInfo> {                      
3440         private Collator mCollator;                                                                      
3441         private PackageManager mPackageManager;                                                          
3442         private HashMap<Object, CharSequence> mLabelCache;                                               
3443         ShortcutNameComparator(PackageManager pm) {                                                      
3444             mPackageManager = pm;                                                                        
3445             mLabelCache = new HashMap<Object, CharSequence>();                                           
3446             mCollator = Collator.getInstance();                                                          
3447         }                                                                                                
3448         ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {            
3449             mPackageManager = pm;                                                                        
3450             mLabelCache = labelCache;                                                                    
3451             mCollator = Collator.getInstance();                                                          
3452         }                                                                                                
3453         public final int compare(ResolveInfo a, ResolveInfo b) {                                         
3454             CharSequence labelA, labelB;                                                                 
3455             ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);                       
3456             ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);                       
3457             if (mLabelCache.containsKey(keyA)) {                                                         
3458                 labelA = mLabelCache.get(keyA);                                                          
3459             } else {                                                                                     
3460                 labelA = a.loadLabel(mPackageManager).toString().trim();                                 
3461                                                                                                          
3462                 mLabelCache.put(keyA, labelA);                                                           
3463             }                                                                                            
3464             if (mLabelCache.containsKey(keyB)) {                                                         
3465                 labelB = mLabelCache.get(keyB);                                                          
3466             } else {                                                                                     
3467                 labelB = b.loadLabel(mPackageManager).toString().trim();                                 
3468                                                                                                          
3469                 mLabelCache.put(keyB, labelB);                                                           
3470             }                                                                                            
3471             return mCollator.compare(labelA, labelB);                                                    
3472         }                                                                                                
3473     };                                                                                                   
3474     public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                  
3475         private Collator mCollator;                                                                      
3476         private PackageManager mPackageManager;                                                          
3477         private HashMap<Object, String> mLabelCache;                                                     
3478         WidgetAndShortcutNameComparator(PackageManager pm) {                                             
3479             mPackageManager = pm;                                                                        
3480             mLabelCache = new HashMap<Object, String>();                                                 
3481             mCollator = Collator.getInstance();                                                          
3482         }                                                                                                
3483         public final int compare(Object a, Object b) {                                                   
3484             String labelA, labelB;                                                                       
3485             if (mLabelCache.containsKey(a)) {                                                            
3486                 labelA = mLabelCache.get(a);                                                             
3487             } else {                                                                                     
3488                 labelA = (a instanceof AppWidgetProviderInfo) ?                                          
3489                     ((AppWidgetProviderInfo) a).label :                                                  
3490                     ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                      
3491                 mLabelCache.put(a, labelA);                                                              
3492             }                                                                                            
3493             if (mLabelCache.containsKey(b)) {                                                            
3494                 labelB = mLabelCache.get(b);                                                             
3495             } else {                                                                                     
3496                 labelB = (b instanceof AppWidgetProviderInfo) ?                                          
3497                     ((AppWidgetProviderInfo) b).label :                                                  
3498                     ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                      
3499                 mLabelCache.put(b, labelB);                                                              
3500             }                                                                                            
3501             return mCollator.compare(labelA, labelB);                                                    
3502         }                                                                                                
3503     };                                                                                                   
3504                                                                                                          
3505     public void dumpState() {                                                                            
3506         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3507         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3508         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3509         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3510         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3511         if (mLoaderTask != null) {                                                                       
3512             mLoaderTask.dumpState();                                                                     
3513         } else {                                                                                         
3514             Log.d(TAG, "mLoaderTask=null");                                                              
3515         }                                                                                                
3516     }                                                                                                    
3517 }                                                                                                        



















































































































































































   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16                                                                                                          
  17 package com.android.launcher3;                                                                           
  18                                                                                                          
  19 import android.app.SearchManager;                                                                        
  20 import android.appwidget.AppWidgetManager;                                                               
  21 import android.appwidget.AppWidgetProviderInfo;                                                          
  22 import android.content.*;                                                                                
  23 import android.content.Intent.ShortcutIconResource;                                                      
  24 import android.content.pm.ActivityInfo;                                                                  
  25 import android.content.pm.PackageInfo;                                                                   
  26 import android.content.pm.PackageManager;                                                                
  27 import android.content.pm.PackageManager.NameNotFoundException;                                          
  28 import android.content.pm.ResolveInfo;                                                                   
  29 import android.content.res.Configuration;                                                                
  30 import android.content.res.Resources;                                                                    
  31 import android.database.Cursor;                                                                          
  32 import android.graphics.Bitmap;                                                                          
  33 import android.graphics.BitmapFactory;                                                                   
  34 import android.net.Uri;                                                                                  
  35 import android.os.Environment;                                                                           
  36 import android.os.Handler;                                                                               
  37 import android.os.HandlerThread;                                                                         
  38 import android.os.Parcelable;                                                                            
  39 import android.os.Process;                                                                               
  40 import android.os.RemoteException;                                                                       
  41 import android.os.SystemClock;                                                                           
  42 import android.provider.BaseColumns;                                                                     
  43 import android.text.TextUtils;                                                                           
  44 import android.util.Log;                                                                                 
  45 import android.util.Pair;                                                                                
  46                                                                                                          
  47 import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;                            
  48                                                                                                          
  49 import java.lang.ref.WeakReference;                                                                      
  50 import java.net.URISyntaxException;                                                                      
  51 import java.text.Collator;                                                                               
  52 import java.util.ArrayList;                                                                              
  53 import java.util.Arrays;                                                                                 
  54 import java.util.Collection;                                                                             
  55 import java.util.Collections;                                                                            
  56 import java.util.Comparator;                                                                             
  57 import java.util.HashMap;                                                                                
  58 import java.util.HashSet;                                                                                
  59 import java.util.Iterator;                                                                               
  60 import java.util.List;                                                                                   
  61 import java.util.Set;                                                                                    
  62 import java.util.TreeMap;                                                                                
  63 import java.util.concurrent.atomic.AtomicBoolean;                                                        
  64                                                                                                          
  65 /**                                                                                                      
  66  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  67  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  68  * for the Launcher.                                                                                     
  69  */                                                                                                      
  70 public class LauncherModel extends BroadcastReceiver {                                                   
  71     static final boolean DEBUG_LOADERS = false;                                                          
  72     static final String TAG = "Launcher.Model";                                                          
  73                                                                                                          
  74     // true = use a "More Apps" folder for non-workspace apps on upgrade                                 
  75     // false = strew non-workspace apps across the workspace on upgrade                                  
  76     public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;                                    
  77                                                                                                          
  78     public static final int LOADER_FLAG_NONE = 0;                                                        
  79     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  80     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  81                                                                                                          
  82     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
  83     private static final long INVALID_SCREEN_ID = -1L;                                                   
  84                                                                                                          
  85     private final boolean mAppsCanBeOnRemoveableStorage;                                                 
  86     private final boolean mOldContentProviderExists;                                                     
  87                                                                                                          
  88     private final LauncherAppState mApp;                                                                 
  89     private final Object mLock = new Object();                                                           
  90     private DeferredHandler mHandler = new DeferredHandler();                                            
  91     private LoaderTask mLoaderTask;                                                                      
  92     private boolean mIsLoaderTaskRunning;                                                                
  93     private volatile boolean mFlushingWorkerThread;                                                      
  94                                                                                                          
  95     // Specific runnable types that are run on the main thread deferred handler, this allows us to       
  96     // clear all queued binding runnables when the Launcher activity is destroyed.                       
  97     private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                            
  98     private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                           
  99                                                                                                          
 100                                                                                                          
 101     private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");             
 102     static {                                                                                             
 103         sWorkerThread.start();                                                                           
 104     }                                                                                                    
 105     private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                       
 106                                                                                                          
 107     // We start off with everything not loaded.  After that, we assume that                              
 108     // our monitoring of the package manager provides all updates and we never                           
 109     // need to do a requery.  These are only ever touched from the loader thread.                        
 110     private boolean mWorkspaceLoaded;                                                                    
 111     private boolean mAllAppsLoaded;                                                                      
 112                                                                                                          
 113     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 114     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 115     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 116     // a normal load, we also clear this set of Runnables.                                               
 117     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 118                                                                                                          
 119     private WeakReference<Callbacks> mCallbacks;                                                         
 120                                                                                                          
 121     // < only access in worker thread >                                                                  
 122     AllAppsList mBgAllAppsList;                                                                          
 123                                                                                                          
 124     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 125     // other locks, this one can generally be held long-term because we never expect any of these        
 126     // static data structures to be referenced outside of the worker thread except on the first          
 127     // load after configuration change.                                                                  
 128     static final Object sBgLock = new Object();                                                          
 129                                                                                                          
 130     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 131     // LauncherModel to their ids                                                                        
 132     static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                  
 133                                                                                                          
 134     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 135     //       created by LauncherModel that are directly on the home screen (however, no widgets or       
 136     //       shortcuts within folders).                                                                  
 137     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 138                                                                                                          
 139     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 140     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 141         new ArrayList<LauncherAppWidgetInfo>();                                                          
 142                                                                                                          
 143     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 144     static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                 
 145                                                                                                          
 146     // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database      
 147     static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                 
 148                                                                                                          
 149     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 150     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 151                                                                                                          
 152     // </ only access in worker thread >                                                                 
 153                                                                                                          
 154     private IconCache mIconCache;                                                                        
 155     private Bitmap mDefaultIcon;                                                                         
 156                                                                                                          
 157     protected int mPreviousConfigMcc;                                                                    
 158                                                                                                          
 159     public interface Callbacks {                                                                         
 160         public boolean setLoadOnResume();                                                                
 161         public int getCurrentWorkspaceScreen();                                                          
 162         public void startBinding();                                                                      
 163         public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                         
 164                               boolean forceAnimateIcons);                                                
 165         public void bindScreens(ArrayList<Long> orderedScreenIds);                                       
 166         public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                    
 167         public void bindFolders(HashMap<Long,FolderInfo> folders);                                       
 168         public void finishBindingItems(boolean upgradePath);                                             
 169         public void bindAppWidget(LauncherAppWidgetInfo info);                                           
 170         public void bindAllApplications(ArrayList<AppInfo> apps);                                        
 171         public void bindAppsAdded(ArrayList<Long> newScreens,                                            
 172                                   ArrayList<ItemInfo> addNotAnimated,                                    
 173                                   ArrayList<ItemInfo> addAnimated,                                       
 174                                   ArrayList<AppInfo> addedApps);                                         
 175         public void bindAppsUpdated(ArrayList<AppInfo> apps);                                            
 176         public void bindComponentsRemoved(ArrayList<String> packageNames,                                
 177                         ArrayList<AppInfo> appInfos);                                                    
 178         public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                          
 179         public void bindSearchablesChanged();                                                            
 180         public boolean isAllAppsButtonRank(int rank);                                                    
 181         public void onPageBoundSynchronously(int page);                                                  
 182         public void dumpLogsToLocalData();                                                               
 183     }                                                                                                    
 184                                                                                                          
 185     public interface ItemInfoFilter {                                                                    
 186         public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                     
 187     }                                                                                                    
 188                                                                                                          
 189     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 190         Context context = app.getContext();                                                              
 191         ContentResolver contentResolver = context.getContentResolver();                                  
 192                                                                                                          
 193         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 194         mOldContentProviderExists = (contentResolver.acquireContentProviderClient(                       
 195                 LauncherSettings.Favorites.OLD_CONTENT_URI) != null);                                    
 196         mApp = app;                                                                                      
 197         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 198         mIconCache = iconCache;                                                                          
 199                                                                                                          
 200         final Resources res = context.getResources();                                                    
 201         Configuration config = res.getConfiguration();                                                   
 202         mPreviousConfigMcc = config.mcc;                                                                 
 203     }                                                                                                    
 204                                                                                                          
 205     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 206      * posted on the main thread handler. */                                                             
 207     private void runOnMainThread(Runnable r) {                                                           
 208         runOnMainThread(r, 0);                                                                           
 209     }                                                                                                    
 210     private void runOnMainThread(Runnable r, int type) {                                                 
 211         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 212             // If we are on the worker thread, post onto the main handler                                
 213             mHandler.post(r);                                                                            
 214         } else {                                                                                         
 215             r.run();                                                                                     
 216         }                                                                                                
 217     }                                                                                                    
 218                                                                                                          
 219     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 220      * posted on the worker thread handler. */                                                           
 221     private static void runOnWorkerThread(Runnable r) {                                                  
 222         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 223             r.run();                                                                                     
 224         } else {                                                                                         
 225             // If we are not on the worker thread, then post to the worker handler                       
 226             sWorker.post(r);                                                                             
 227         }                                                                                                
 228     }                                                                                                    
 229                                                                                                          
 230     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 231         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 232     }                                                                                                    
 233                                                                                                          
 234     static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy,               
 235                                  long screen) {                                                          
 236         LauncherAppState app = LauncherAppState.getInstance();                                           
 237         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 238         final int xCount = (int) grid.numColumns;                                                        
 239         final int yCount = (int) grid.numRows;                                                           
 240         boolean[][] occupied = new boolean[xCount][yCount];                                              
 241                                                                                                          
 242         int cellX, cellY, spanX, spanY;                                                                  
 243         for (int i = 0; i < items.size(); ++i) {                                                         
 244             final ItemInfo item = items.get(i);                                                          
 245             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                        
 246                 if (item.screenId == screen) {                                                           
 247                     cellX = item.cellX;                                                                  
 248                     cellY = item.cellY;                                                                  
 249                     spanX = item.spanX;                                                                  
 250                     spanY = item.spanY;                                                                  
 251                     for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {                
 252                         for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {            
 253                             occupied[x][y] = true;                                                       
 254                         }                                                                                
 255                     }                                                                                    
 256                 }                                                                                        
 257             }                                                                                            
 258         }                                                                                                
 259                                                                                                          
 260         return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);                            
 261     }                                                                                                    
 262     static Pair<Long, int[]> findNextAvailableIconSpace(Context context, String name,                    
 263                                                         Intent launchIntent,                             
 264                                                         int firstScreenIndex,                            
 265                                                         ArrayList<Long> workspaceScreens) {              
 266         // Lock on the app so that we don't try and get the items while apps are being added             
 267         LauncherAppState app = LauncherAppState.getInstance();                                           
 268         LauncherModel model = app.getModel();                                                            
 269         boolean found = false;                                                                           
 270         synchronized (app) {                                                                             
 271             if (sWorkerThread.getThreadId() != Process.myTid()) {                                        
 272                 // Flush the LauncherModel worker thread, so that if we just did another                 
 273                 // processInstallShortcut, we give it time for its shortcut to get added to the          
 274                 // database (getItemsInLocalCoordinates reads the database)                              
 275                 model.flushWorkerThread();                                                               
 276             }                                                                                            
 277             final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);         
 278                                                                                                          
 279             // Try adding to the workspace screens incrementally, starting at the default or center      
 280             // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))       
 281             firstScreenIndex = Math.min(firstScreenIndex, workspaceScreens.size());                      
 282             int count = workspaceScreens.size();                                                         
 283             for (int screen = firstScreenIndex; screen < count && !found; screen++) {                    
 284                 int[] tmpCoordinates = new int[2];                                                       
 285                 if (findNextAvailableIconSpaceInScreen(items, tmpCoordinates,                            
 286                         workspaceScreens.get(screen))) {                                                 
 287                     // Update the Launcher db                                                            
 288                     return new Pair<Long, int[]>(workspaceScreens.get(screen), tmpCoordinates);          
 289                 }                                                                                        
 290             }                                                                                            
 291         }                                                                                                
 292         return null;                                                                                     
 293     }                                                                                                    
 294                                                                                                          
 295     public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps,      
 296                                     final ArrayList<AppInfo> allAppsApps) {                              
 297         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                     
 298         addAndBindAddedApps(context, workspaceApps, cb, allAppsApps);                                    
 299     }                                                                                                    
 300     public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps,      
 301                                 final Callbacks callbacks, final ArrayList<AppInfo> allAppsApps) {       
 302         if (workspaceApps == null || allAppsApps == null) {                                              
 303             throw new RuntimeException("workspaceApps and allAppsApps must not be null");                
 304         }                                                                                                
 305         if (workspaceApps.isEmpty() && allAppsApps.isEmpty()) {                                          
 306             return;                                                                                      
 307         }                                                                                                
 308         // Process the newly added applications and add them to the database first                       
 309         Runnable r = new Runnable() {                                                                    
 310             public void run() {                                                                          
 311                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 312                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 313                                                                                                          
 314                 // Get the list of workspace screens.  We need to append to this list and                
 315                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 316                 // called.                                                                               
 317                 ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                
 318                 TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                 
 319                 for (Integer i : orderedScreens.keySet()) {                                              
 320                     long screenId = orderedScreens.get(i);                                               
 321                     workspaceScreens.add(screenId);                                                      
 322                 }                                                                                        
 323                                                                                                          
 324                 synchronized(sBgLock) {                                                                  
 325                     Iterator<ItemInfo> iter = workspaceApps.iterator();                                  
 326                     while (iter.hasNext()) {                                                             
 327                         ItemInfo a = iter.next();                                                        
 328                         final String name = a.title.toString();                                          
 329                         final Intent launchIntent = a.getIntent();                                       
 330                                                                                                          
 331                         // Short-circuit this logic if the icon exists somewhere on the workspace        
 332                         if (LauncherModel.shortcutExists(context, name, launchIntent)) {                 
 333                             continue;                                                                    
 334                         }                                                                                
 335                                                                                                          
 336                         // Add this icon to the db, creating a new page if necessary.  If there          
 337                         // is only the empty page then we just add items to the first page.              
 338                         // Otherwise, we add them to the next pages.                                     
 339                         int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;                   
 340                         Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,     
 341                                 name, launchIntent, startSearchPageIndex, workspaceScreens);             
 342                         if (coords == null) {                                                            
 343                             LauncherProvider lp = LauncherAppState.getLauncherProvider();                
 344                                                                                                          
 345                             // If we can't find a valid position, then just add a new screen.            
 346                             // This takes time so we need to re-queue the add until the new              
 347                             // page is added.  Create as many screens as necessary to satisfy            
 348                             // the startSearchPageIndex.                                                 
 349                             int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -                   
 350                                     workspaceScreens.size());                                            
 351                             while (numPagesToAdd > 0) {                                                  
 352                                 long screenId = lp.generateNewScreenId();                                
 353                                 // Save the screen id for binding in the workspace                       
 354                                 workspaceScreens.add(screenId);                                          
 355                                 addedWorkspaceScreensFinal.add(screenId);                                
 356                                 numPagesToAdd--;                                                         
 357                             }                                                                            
 358                                                                                                          
 359                             // Find the coordinate again                                                 
 360                             coords = LauncherModel.findNextAvailableIconSpace(context,                   
 361                                     name, launchIntent, startSearchPageIndex, workspaceScreens);         
 362                         }                                                                                
 363                         if (coords == null) {                                                            
 364                             throw new RuntimeException("Coordinates should not be null");                
 365                         }                                                                                
 366                                                                                                          
 367                         ShortcutInfo shortcutInfo;                                                       
 368                         if (a instanceof ShortcutInfo) {                                                 
 369                             shortcutInfo = (ShortcutInfo) a;                                             
 370                         } else if (a instanceof AppInfo) {                                               
 371                             shortcutInfo = ((AppInfo) a).makeShortcut();                                 
 372                         } else {                                                                         
 373                             throw new RuntimeException("Unexpected info type");                          
 374                         }                                                                                
 375                                                                                                          
 376                         // Add the shortcut to the db                                                    
 377                         addItemToDatabase(context, shortcutInfo,                                         
 378                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 379                                 coords.first, coords.second[0], coords.second[1], false);                
 380                         // Save the ShortcutInfo for binding in the workspace                            
 381                         addedShortcutsFinal.add(shortcutInfo);                                           
 382                     }                                                                                    
 383                 }                                                                                        
 384                                                                                                          
 385                 // Update the workspace screens                                                          
 386                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 387                                                                                                          
 388                 if (!addedShortcutsFinal.isEmpty() || !allAppsApps.isEmpty()) {                          
 389                     runOnMainThread(new Runnable() {                                                     
 390                         public void run() {                                                              
 391                             Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                 
 392                             if (callbacks == cb && cb != null) {                                         
 393                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 394                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 395                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 396                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 397                                     long lastScreenId = info.screenId;                                   
 398                                     for (ItemInfo i : addedShortcutsFinal) {                             
 399                                         if (i.screenId == lastScreenId) {                                
 400                                             addAnimated.add(i);                                          
 401                                         } else {                                                         
 402                                             addNotAnimated.add(i);                                       
 403                                         }                                                                
 404                                     }                                                                    
 405                                 }                                                                        
 406                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 407                                         addNotAnimated, addAnimated, allAppsApps);                       
 408                             }                                                                            
 409                         }                                                                                
 410                     });                                                                                  
 411                 }                                                                                        
 412             }                                                                                            
 413         };                                                                                               
 414         runOnWorkerThread(r);                                                                            
 415     }                                                                                                    
 416 <<<<<<< MINE                                                                                             
 417 ||||||| BASE                                                                                             
 418 public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                  
 419         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                        
 420                                                                                                          
 421         if (allAppsApps == null) {                                                                       
 422             throw new RuntimeException("allAppsApps must not be null");                                  
 423         }                                                                                                
 424         if (allAppsApps.isEmpty()) {                                                                     
 425             return;                                                                                      
 426         }                                                                                                
 427                                                                                                          
 428         // Process the newly added applications and add them to the database first                       
 429         Runnable r = new Runnable() {                                                                    
 430             public void run() {                                                                          
 431                 runOnMainThread(new Runnable() {                                                         
 432                     public void run() {                                                                  
 433                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
 434                         if (callbacks == cb && cb != null) {                                             
 435                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 436                         }                                                                                
 437                     }                                                                                    
 438                 });                                                                                      
 439             }                                                                                            
 440         };                                                                                               
 441         runOnWorkerThread(r);                                                                            
 442     }                                                                                                    
 443 =======                                                                                                  
 444 public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                  
 445         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                        
 446                                                                                                          
 447         if (allAppsApps == null) {                                                                       
 448             throw new RuntimeException("allAppsApps must not be null");                                  
 449         }                                                                                                
 450         if (allAppsApps.isEmpty()) {                                                                     
 451             return;                                                                                      
 452         }                                                                                                
 453                                                                                                          
 454         final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();                           
 455         Iterator<AppInfo> iter = allAppsApps.iterator();                                                 
 456         while (iter.hasNext()) {                                                                         
 457             ItemInfo a = iter.next();                                                                    
 458             if (LauncherModel.appWasRestored(ctx, a.getIntent())) {                                      
 459                 restoredAppsFinal.add((AppInfo) a);                                                      
 460             }                                                                                            
 461         }                                                                                                
 462                                                                                                          
 463         // Process the newly added applications and add them to the database first                       
 464         Runnable r = new Runnable() {                                                                    
 465             public void run() {                                                                          
 466                 runOnMainThread(new Runnable() {                                                         
 467                     public void run() {                                                                  
 468                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
 469                         if (callbacks == cb && cb != null) {                                             
 470                             callbacks.bindAppsAdded(null, null, null, allAppsApps);                      
 471                             if (!restoredAppsFinal.isEmpty()) {                                          
 472                                 callbacks.bindAppsUpdated(restoredAppsFinal);                            
 473                             }                                                                            
 474                         }                                                                                
 475                     }                                                                                    
 476                 });                                                                                      
 477             }                                                                                            
 478         };                                                                                               
 479         runOnWorkerThread(r);                                                                            
 480     }                                                                                                    
 481 >>>>>>> YOURS                                                                                            
 482 <<<<<<< MINE                                                                                             
 483 ||||||| BASE                                                                                             
 484 public void addAndBindAddedWorkspaceApps(final Context context,                                          
 485             final ArrayList<ItemInfo> workspaceApps) {                                                   
 486         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                        
 487                                                                                                          
 488         if (workspaceApps == null) {                                                                     
 489             throw new RuntimeException("workspaceApps and allAppsApps must not be null");                
 490         }                                                                                                
 491         if (workspaceApps.isEmpty()) {                                                                   
 492             return;                                                                                      
 493         }                                                                                                
 494         // Process the newly added applications and add them to the database first                       
 495         Runnable r = new Runnable() {                                                                    
 496             public void run() {                                                                          
 497                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 498                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 499                                                                                                          
 500                 // Get the list of workspace screens.  We need to append to this list and                
 501                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 502                 // called.                                                                               
 503                 ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                
 504                 TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                 
 505                 for (Integer i : orderedScreens.keySet()) {                                              
 506                     long screenId = orderedScreens.get(i);                                               
 507                     workspaceScreens.add(screenId);                                                      
 508                 }                                                                                        
 509                                                                                                          
 510                 synchronized(sBgLock) {                                                                  
 511                     Iterator<ItemInfo> iter = workspaceApps.iterator();                                  
 512                     while (iter.hasNext()) {                                                             
 513                         ItemInfo a = iter.next();                                                        
 514                         final String name = a.title.toString();                                          
 515                         final Intent launchIntent = a.getIntent();                                       
 516                                                                                                          
 517                         // Short-circuit this logic if the icon exists somewhere on the workspace        
 518                         if (LauncherModel.shortcutExists(context, name, launchIntent)) {                 
 519                             continue;                                                                    
 520                         }                                                                                
 521                                                                                                          
 522                         // Add this icon to the db, creating a new page if necessary.  If there          
 523                         // is only the empty page then we just add items to the first page.              
 524                         // Otherwise, we add them to the next pages.                                     
 525                         int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;                   
 526                         Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,     
 527                                 name, launchIntent, startSearchPageIndex, workspaceScreens);             
 528                         if (coords == null) {                                                            
 529                             LauncherProvider lp = LauncherAppState.getLauncherProvider();                
 530                                                                                                          
 531                             // If we can't find a valid position, then just add a new screen.            
 532                             // This takes time so we need to re-queue the add until the new              
 533                             // page is added.  Create as many screens as necessary to satisfy            
 534                             // the startSearchPageIndex.                                                 
 535                             int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -                   
 536                                     workspaceScreens.size());                                            
 537                             while (numPagesToAdd > 0) {                                                  
 538                                 long screenId = lp.generateNewScreenId();                                
 539                                 // Save the screen id for binding in the workspace                       
 540                                 workspaceScreens.add(screenId);                                          
 541                                 addedWorkspaceScreensFinal.add(screenId);                                
 542                                 numPagesToAdd--;                                                         
 543                             }                                                                            
 544                                                                                                          
 545                             // Find the coordinate again                                                 
 546                             coords = LauncherModel.findNextAvailableIconSpace(context,                   
 547                                     name, launchIntent, startSearchPageIndex, workspaceScreens);         
 548                         }                                                                                
 549                         if (coords == null) {                                                            
 550                             throw new RuntimeException("Coordinates should not be null");                
 551                         }                                                                                
 552                                                                                                          
 553                         ShortcutInfo shortcutInfo;                                                       
 554                         if (a instanceof ShortcutInfo) {                                                 
 555                             shortcutInfo = (ShortcutInfo) a;                                             
 556                         } else if (a instanceof AppInfo) {                                               
 557                             shortcutInfo = ((AppInfo) a).makeShortcut();                                 
 558                         } else {                                                                         
 559                             throw new RuntimeException("Unexpected info type");                          
 560                         }                                                                                
 561                                                                                                          
 562                         // Add the shortcut to the db                                                    
 563                         addItemToDatabase(context, shortcutInfo,                                         
 564                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 565                                 coords.first, coords.second[0], coords.second[1], false);                
 566                         // Save the ShortcutInfo for binding in the workspace                            
 567                         addedShortcutsFinal.add(shortcutInfo);                                           
 568                     }                                                                                    
 569                 }                                                                                        
 570                                                                                                          
 571                 // Update the workspace screens                                                          
 572                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 573                                                                                                          
 574                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 575                     runOnMainThread(new Runnable() {                                                     
 576                         public void run() {                                                              
 577                             Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                 
 578                             if (callbacks == cb && cb != null) {                                         
 579                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 580                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 581                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 582                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 583                                     long lastScreenId = info.screenId;                                   
 584                                     for (ItemInfo i : addedShortcutsFinal) {                             
 585                                         if (i.screenId == lastScreenId) {                                
 586                                             addAnimated.add(i);                                          
 587                                         } else {                                                         
 588                                             addNotAnimated.add(i);                                       
 589                                         }                                                                
 590                                     }                                                                    
 591                                 }                                                                        
 592                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 593                                         addNotAnimated, addAnimated, null);                              
 594                             }                                                                            
 595                         }                                                                                
 596                     });                                                                                  
 597                 }                                                                                        
 598             }                                                                                            
 599         };                                                                                               
 600         runOnWorkerThread(r);                                                                            
 601     }                                                                                                    
 602 =======                                                                                                  
 603 public void addAndBindAddedWorkspaceApps(final Context context,                                          
 604             final ArrayList<ItemInfo> workspaceApps) {                                                   
 605         final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                        
 606                                                                                                          
 607         if (workspaceApps == null) {                                                                     
 608             throw new RuntimeException("workspaceApps and allAppsApps must not be null");                
 609         }                                                                                                
 610         if (workspaceApps.isEmpty()) {                                                                   
 611             return;                                                                                      
 612         }                                                                                                
 613         // Process the newly added applications and add them to the database first                       
 614         Runnable r = new Runnable() {                                                                    
 615             public void run() {                                                                          
 616                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 617                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 618                 final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();                   
 619                                                                                                          
 620                 // Get the list of workspace screens.  We need to append to this list and                
 621                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 622                 // called.                                                                               
 623                 ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                
 624                 TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                 
 625                 for (Integer i : orderedScreens.keySet()) {                                              
 626                     long screenId = orderedScreens.get(i);                                               
 627                     workspaceScreens.add(screenId);                                                      
 628                 }                                                                                        
 629                                                                                                          
 630                 synchronized(sBgLock) {                                                                  
 631                     Iterator<ItemInfo> iter = workspaceApps.iterator();                                  
 632                     while (iter.hasNext()) {                                                             
 633                         ItemInfo a = iter.next();                                                        
 634                         final String name = a.title.toString();                                          
 635                         final Intent launchIntent = a.getIntent();                                       
 636                                                                                                          
 637                         // Short-circuit this logic if the icon exists somewhere on the workspace        
 638                         if (LauncherModel.shortcutExists(context, name, launchIntent)) {                 
 639                             // Only InstallShortcutReceiver sends us shortcutInfos, ignore them          
 640                             if (a instanceof AppInfo &&                                                  
 641                                     LauncherModel.appWasRestored(context, launchIntent)) {               
 642                                 restoredAppsFinal.add((AppInfo) a);                                      
 643                             }                                                                            
 644                             continue;                                                                    
 645                         }                                                                                
 646                                                                                                          
 647                         // Add this icon to the db, creating a new page if necessary.  If there          
 648                         // is only the empty page then we just add items to the first page.              
 649                         // Otherwise, we add them to the next pages.                                     
 650                         int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;                   
 651                         Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,     
 652                                 name, launchIntent, startSearchPageIndex, workspaceScreens);             
 653                         if (coords == null) {                                                            
 654                             LauncherProvider lp = LauncherAppState.getLauncherProvider();                
 655                                                                                                          
 656                             // If we can't find a valid position, then just add a new screen.            
 657                             // This takes time so we need to re-queue the add until the new              
 658                             // page is added.  Create as many screens as necessary to satisfy            
 659                             // the startSearchPageIndex.                                                 
 660                             int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -                   
 661                                     workspaceScreens.size());                                            
 662                             while (numPagesToAdd > 0) {                                                  
 663                                 long screenId = lp.generateNewScreenId();                                
 664                                 // Save the screen id for binding in the workspace                       
 665                                 workspaceScreens.add(screenId);                                          
 666                                 addedWorkspaceScreensFinal.add(screenId);                                
 667                                 numPagesToAdd--;                                                         
 668                             }                                                                            
 669                                                                                                          
 670                             // Find the coordinate again                                                 
 671                             coords = LauncherModel.findNextAvailableIconSpace(context,                   
 672                                     name, launchIntent, startSearchPageIndex, workspaceScreens);         
 673                         }                                                                                
 674                         if (coords == null) {                                                            
 675                             throw new RuntimeException("Coordinates should not be null");                
 676                         }                                                                                
 677                                                                                                          
 678                         ShortcutInfo shortcutInfo;                                                       
 679                         if (a instanceof ShortcutInfo) {                                                 
 680                             shortcutInfo = (ShortcutInfo) a;                                             
 681                         } else if (a instanceof AppInfo) {                                               
 682                             shortcutInfo = ((AppInfo) a).makeShortcut();                                 
 683                         } else {                                                                         
 684                             throw new RuntimeException("Unexpected info type");                          
 685                         }                                                                                
 686                                                                                                          
 687                         // Add the shortcut to the db                                                    
 688                         addItemToDatabase(context, shortcutInfo,                                         
 689                                 LauncherSettings.Favorites.CONTAINER_DESKTOP,                            
 690                                 coords.first, coords.second[0], coords.second[1], false);                
 691                         // Save the ShortcutInfo for binding in the workspace                            
 692                         addedShortcutsFinal.add(shortcutInfo);                                           
 693                     }                                                                                    
 694                 }                                                                                        
 695                                                                                                          
 696                 // Update the workspace screens                                                          
 697                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 698                                                                                                          
 699                 if (!addedShortcutsFinal.isEmpty()) {                                                    
 700                     runOnMainThread(new Runnable() {                                                     
 701                         public void run() {                                                              
 702                             Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                 
 703                             if (callbacks == cb && cb != null) {                                         
 704                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 705                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 706                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 707                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 708                                     long lastScreenId = info.screenId;                                   
 709                                     for (ItemInfo i : addedShortcutsFinal) {                             
 710                                         if (i.screenId == lastScreenId) {                                
 711                                             addAnimated.add(i);                                          
 712                                         } else {                                                         
 713                                             addNotAnimated.add(i);                                       
 714                                         }                                                                
 715                                     }                                                                    
 716                                 }                                                                        
 717                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                      
 718                                         addNotAnimated, addAnimated, null);                              
 719                                 if (!restoredAppsFinal.isEmpty()) {                                      
 720                                     callbacks.bindAppsUpdated(restoredAppsFinal);                        
 721                                 }                                                                        
 722                             }                                                                            
 723                         }                                                                                
 724                     });                                                                                  
 725                 }                                                                                        
 726             }                                                                                            
 727         };                                                                                               
 728         runOnWorkerThread(r);                                                                            
 729     }                                                                                                    
 730 >>>>>>> YOURS                                                                                            
 731                                                                                                          
 732                                                                                                          
 733     public Bitmap getFallbackIcon() {                                                                    
 734         if (mDefaultIcon == null) {                                                                      
 735             final Context context = LauncherAppState.getInstance().getContext();                         
 736             mDefaultIcon = Utilities.createIconBitmap(                                                   
 737                     mIconCache.getFullResDefaultActivityIcon(), context);                                
 738         }                                                                                                
 739         return Bitmap.createBitmap(mDefaultIcon);                                                        
 740     }                                                                                                    
 741                                                                                                          
 742     public void unbindItemInfosAndClearQueuedBindRunnables() {                                           
 743         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 744             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 745                     "main thread");                                                                      
 746         }                                                                                                
 747                                                                                                          
 748         // Clear any deferred bind runnables                                                             
 749         mDeferredBindRunnables.clear();                                                                  
 750         // Remove any queued bind runnables                                                              
 751         mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                 
 752         // Unbind all the workspace items                                                                
 753         unbindWorkspaceItemsOnMainThread();                                                              
 754     }                                                                                                    
 755                                                                                                          
 756     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 757     void unbindWorkspaceItemsOnMainThread() {                                                            
 758         // Ensure that we don't use the same workspace items data structure on the main thread           
 759         // by making a copy of workspace items first.                                                    
 760         final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                         
 761         final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                             
 762         synchronized (sBgLock) {                                                                         
 763             tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                 
 764             tmpAppWidgets.addAll(sBgAppWidgets);                                                         
 765         }                                                                                                
 766         Runnable r = new Runnable() {                                                                    
 767                 @Override                                                                                
 768                 public void run() {                                                                      
 769                    for (ItemInfo item : tmpWorkspaceItems) {                                             
 770                        item.unbind();                                                                    
 771                    }                                                                                     
 772                    for (ItemInfo item : tmpAppWidgets) {                                                 
 773                        item.unbind();                                                                    
 774                    }                                                                                     
 775                 }                                                                                        
 776             };                                                                                           
 777         runOnMainThread(r);                                                                              
 778     }                                                                                                    
 779                                                                                                          
 780     /**                                                                                                  
 781      * Adds an item to the DB if it was not created previously, or move it to a new                      
 782      * <container, screen, cellX, cellY>                                                                 
 783      */                                                                                                  
 784     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 785             long screenId, int cellX, int cellY) {                                                       
 786         if (item.container == ItemInfo.NO_ID) {                                                          
 787             // From all apps                                                                             
 788             addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                  
 789         } else {                                                                                         
 790             // From somewhere else                                                                       
 791             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 792         }                                                                                                
 793     }                                                                                                    
 794                                                                                                          
 795     static void checkItemInfoLocked(                                                                     
 796             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 797         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 798         if (modelItem != null && item != modelItem) {                                                    
 799             // check all the data is consistent                                                          
 800             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 801                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 802                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 803                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 804                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 805                         modelShortcut.id == shortcut.id &&                                               
 806                         modelShortcut.itemType == shortcut.itemType &&                                   
 807                         modelShortcut.container == shortcut.container &&                                 
 808                         modelShortcut.screenId == shortcut.screenId &&                                   
 809                         modelShortcut.cellX == shortcut.cellX &&                                         
 810                         modelShortcut.cellY == shortcut.cellY &&                                         
 811                         modelShortcut.spanX == shortcut.spanX &&                                         
 812                         modelShortcut.spanY == shortcut.spanY &&                                         
 813                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 814                         (modelShortcut.dropPos != null &&                                                
 815                                 shortcut.dropPos != null &&                                              
 816                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 817                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 818                     // For all intents and purposes, this is the same object                             
 819                     return;                                                                              
 820                 }                                                                                        
 821             }                                                                                            
 822                                                                                                          
 823             // the modelItem needs to match up perfectly with item if our model is                       
 824             // to be consistent with the database-- for now, just require                                
 825             // modelItem == item or the equality check above                                             
 826             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 827                     "modelItem: " +                                                                      
 828                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 829                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 830             RuntimeException e = new RuntimeException(msg);                                              
 831             if (stackTrace != null) {                                                                    
 832                 e.setStackTrace(stackTrace);                                                             
 833             }                                                                                            
 834             throw e;                                                                                     
 835         }                                                                                                
 836     }                                                                                                    
 837                                                                                                          
 838     static void checkItemInfo(final ItemInfo item) {                                                     
 839         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 840         final long itemId = item.id;                                                                     
 841         Runnable r = new Runnable() {                                                                    
 842             public void run() {                                                                          
 843                 synchronized (sBgLock) {                                                                 
 844                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 845                 }                                                                                        
 846             }                                                                                            
 847         };                                                                                               
 848         runOnWorkerThread(r);                                                                            
 849     }                                                                                                    
 850                                                                                                          
 851     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 852             final ItemInfo item, final String callingFunction) {                                         
 853         final long itemId = item.id;                                                                     
 854         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                         
 855         final ContentResolver cr = context.getContentResolver();                                         
 856                                                                                                          
 857         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 858         Runnable r = new Runnable() {                                                                    
 859             public void run() {                                                                          
 860                 cr.update(uri, values, null, null);                                                      
 861                 updateItemArrays(item, itemId, stackTrace);                                              
 862             }                                                                                            
 863         };                                                                                               
 864         runOnWorkerThread(r);                                                                            
 865     }                                                                                                    
 866                                                                                                          
 867     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 868             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 869         final ContentResolver cr = context.getContentResolver();                                         
 870                                                                                                          
 871         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 872         Runnable r = new Runnable() {                                                                    
 873             public void run() {                                                                          
 874                 ArrayList<ContentProviderOperation> ops =                                                
 875                         new ArrayList<ContentProviderOperation>();                                       
 876                 int count = items.size();                                                                
 877                 for (int i = 0; i < count; i++) {                                                        
 878                     ItemInfo item = items.get(i);                                                        
 879                     final long itemId = item.id;                                                         
 880                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);             
 881                     ContentValues values = valuesList.get(i);                                            
 882                                                                                                          
 883                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 884                     updateItemArrays(item, itemId, stackTrace);                                          
 885                                                                                                          
 886                 }                                                                                        
 887                 try {                                                                                    
 888                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 889                 } catch (Exception e) {                                                                  
 890                     e.printStackTrace();                                                                 
 891                 }                                                                                        
 892             }                                                                                            
 893         };                                                                                               
 894         runOnWorkerThread(r);                                                                            
 895     }                                                                                                    
 896                                                                                                          
 897     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 898         // Lock on mBgLock *after* the db operation                                                      
 899         synchronized (sBgLock) {                                                                         
 900             checkItemInfoLocked(itemId, item, stackTrace);                                               
 901                                                                                                          
 902             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 903                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 904                 // Item is in a folder, make sure this folder exists                                     
 905                 if (!sBgFolders.containsKey(item.container)) {                                           
 906                     // An items container is being set to a that of an item which is not in              
 907                     // the list of Folders.                                                              
 908                     String msg = "item: " + item + " container being set to: " +                         
 909                             item.container + ", not in the list of folders";                             
 910                     Log.e(TAG, msg);                                                                     
 911                 }                                                                                        
 912             }                                                                                            
 913                                                                                                          
 914             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 915             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 916             // that are on the desktop, as appropriate                                                   
 917             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 918             if (modelItem != null &&                                                                     
 919                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 920                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 921                 switch (modelItem.itemType) {                                                            
 922                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 923                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 924                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 925                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 926                             sBgWorkspaceItems.add(modelItem);                                            
 927                         }                                                                                
 928                         break;                                                                           
 929                     default:                                                                             
 930                         break;                                                                           
 931                 }                                                                                        
 932             } else {                                                                                     
 933                 sBgWorkspaceItems.remove(modelItem);                                                     
 934             }                                                                                            
 935         }                                                                                                
 936     }                                                                                                    
 937                                                                                                          
 938     public void flushWorkerThread() {                                                                    
 939         mFlushingWorkerThread = true;                                                                    
 940         Runnable waiter = new Runnable() {                                                               
 941                 public void run() {                                                                      
 942                     synchronized (this) {                                                                
 943                         notifyAll();                                                                     
 944                         mFlushingWorkerThread = false;                                                   
 945                     }                                                                                    
 946                 }                                                                                        
 947             };                                                                                           
 948                                                                                                          
 949         synchronized(waiter) {                                                                           
 950             runOnWorkerThread(waiter);                                                                   
 951             if (mLoaderTask != null) {                                                                   
 952                 synchronized(mLoaderTask) {                                                              
 953                     mLoaderTask.notify();                                                                
 954                 }                                                                                        
 955             }                                                                                            
 956             boolean success = false;                                                                     
 957             while (!success) {                                                                           
 958                 try {                                                                                    
 959                     waiter.wait();                                                                       
 960                     success = true;                                                                      
 961                 } catch (InterruptedException e) {                                                       
 962                 }                                                                                        
 963             }                                                                                            
 964         }                                                                                                
 965     }                                                                                                    
 966                                                                                                          
 967     /**                                                                                                  
 968      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 969      */                                                                                                  
 970     static void moveItemInDatabase(Context context, final ItemInfo item, final long container,           
 971             final long screenId, final int cellX, final int cellY) {                                     
 972         item.container = container;                                                                      
 973         item.cellX = cellX;                                                                              
 974         item.cellY = cellY;                                                                              
 975                                                                                                          
 976         // We store hotseat items in canonical form which is this orientation invariant position         
 977         // in the hotseat                                                                                
 978         if (context instanceof Launcher && screenId < 0 &&                                               
 979                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 980             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 981         } else {                                                                                         
 982             item.screenId = screenId;                                                                    
 983         }                                                                                                
 984                                                                                                          
 985         final ContentValues values = new ContentValues();                                                
 986         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 987         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 988         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 989         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 990                                                                                                          
 991         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 992     }                                                                                                    
 993                                                                                                          
 994     /**                                                                                                  
 995      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 996      * cellX, cellY have already been updated on the ItemInfos.                                          
 997      */                                                                                                  
 998     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 999             final long container, final int screen) {                                                    
1000                                                                                                          
1001         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
1002         int count = items.size();                                                                        
1003                                                                                                          
1004         for (int i = 0; i < count; i++) {                                                                
1005             ItemInfo item = items.get(i);                                                                
1006             item.container = container;                                                                  
1007                                                                                                          
1008             // We store hotseat items in canonical form which is this orientation invariant position     
1009             // in the hotseat                                                                            
1010             if (context instanceof Launcher && screen < 0 &&                                             
1011                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
1012                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
1013                         item.cellY);                                                                     
1014             } else {                                                                                     
1015                 item.screenId = screen;                                                                  
1016             }                                                                                            
1017                                                                                                          
1018             final ContentValues values = new ContentValues();                                            
1019             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
1020             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
1021             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
1022             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
1023                                                                                                          
1024             contentValues.add(values);                                                                   
1025         }                                                                                                
1026         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
1027     }                                                                                                    
1028                                                                                                          
1029     /**                                                                                                  
1030      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
1031      */                                                                                                  
1032     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
1033             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
1034         item.container = container;                                                                      
1035         item.cellX = cellX;                                                                              
1036         item.cellY = cellY;                                                                              
1037         item.spanX = spanX;                                                                              
1038         item.spanY = spanY;                                                                              
1039                                                                                                          
1040         // We store hotseat items in canonical form which is this orientation invariant position         
1041         // in the hotseat                                                                                
1042         if (context instanceof Launcher && screenId < 0 &&                                               
1043                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
1044             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1045         } else {                                                                                         
1046             item.screenId = screenId;                                                                    
1047         }                                                                                                
1048                                                                                                          
1049         final ContentValues values = new ContentValues();                                                
1050         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
1051         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
1052         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
1053         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
1054         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
1055         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
1056                                                                                                          
1057         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
1058     }                                                                                                    
1059                                                                                                          
1060     /**                                                                                                  
1061      * Update an item to the database in a specified container.                                          
1062      */                                                                                                  
1063     static void updateItemInDatabase(Context context, final ItemInfo item) {                             
1064         final ContentValues values = new ContentValues();                                                
1065         item.onAddToDatabase(values);                                                                    
1066         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                
1067         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
1068     }                                                                                                    
1069                                                                                                          
1070     /**                                                                                                  
1071      * Returns true if the shortcuts already exists in the database.                                     
1072      * we identify a shortcut by its title and intent.                                                   
1073      */                                                                                                  
1074     static boolean shortcutExists(Context context, String title, Intent intent) {                        
1075         final ContentResolver cr = context.getContentResolver();                                         
1076         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
1077             new String[] { "title", "intent" }, "title=? and intent=?",                                  
1078             new String[] { title, intent.toUri(0) }, null);                                              
1079         boolean result = false;                                                                          
1080         try {                                                                                            
1081             result = c.moveToFirst();                                                                    
1082         } finally {                                                                                      
1083             c.close();                                                                                   
1084         }                                                                                                
1085         return result;                                                                                   
1086     }                                                                                                    
1087                                                                                                          
1088     /**                                                                                                  
1089      * Returns true if the shortcuts already exists in the database.                                     
1090      * we identify a shortcut by the component name of the intent.                                       
1091      */                                                                                                  
1092     static boolean appWasRestored(Context context, Intent intent) {                                      
1093         final ContentResolver cr = context.getContentResolver();                                         
1094         final ComponentName component = intent.getComponent();                                           
1095         if (component == null) {                                                                         
1096             return false;                                                                                
1097         }                                                                                                
1098         String componentName = component.flattenToString();                                              
1099         final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1";       
1100         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
1101                 new String[]{"intent", "restored"}, where, null, null);                                  
1102         boolean result = false;                                                                          
1103         try {                                                                                            
1104             result = c.moveToFirst();                                                                    
1105         } finally {                                                                                      
1106             c.close();                                                                                   
1107         }                                                                                                
1108         Log.d(TAG, "shortcutWasRestored is " + result + " for " + componentName);                        
1109         return result;                                                                                   
1110     }                                                                                                    
1111                                                                                                          
1112     /**                                                                                                  
1113      * Returns an ItemInfo array containing all the items in the LauncherModel.                          
1114      * The ItemInfo.id is not set through this function.                                                 
1115      */                                                                                                  
1116     static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {                             
1117         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
1118         final ContentResolver cr = context.getContentResolver();                                         
1119         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {                       
1120                 LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,              
1121                 LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Fav🔵
1122                 LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null); 
1123                                                                                                          
1124         final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);         
1125         final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);        
1126         final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);              
1127         final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                
1128         final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                
1129         final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                
1130         final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                
1131                                                                                                          
1132         try {                                                                                            
1133             while (c.moveToNext()) {                                                                     
1134                 ItemInfo item = new ItemInfo();                                                          
1135                 item.cellX = c.getInt(cellXIndex);                                                       
1136                 item.cellY = c.getInt(cellYIndex);                                                       
1137                 item.spanX = Math.max(1, c.getInt(spanXIndex));                                          
1138                 item.spanY = Math.max(1, c.getInt(spanYIndex));                                          
1139                 item.container = c.getInt(containerIndex);                                               
1140                 item.itemType = c.getInt(itemTypeIndex);                                                 
1141                 item.screenId = c.getInt(screenIndex);                                                   
1142                                                                                                          
1143                 items.add(item);                                                                         
1144             }                                                                                            
1145         } catch (Exception e) {                                                                          
1146             items.clear();                                                                               
1147         } finally {                                                                                      
1148             c.close();                                                                                   
1149         }                                                                                                
1150                                                                                                          
1151         return items;                                                                                    
1152     }                                                                                                    
1153                                                                                                          
1154     /**                                                                                                  
1155      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
1156      */                                                                                                  
1157     FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {            
1158         final ContentResolver cr = context.getContentResolver();                                         
1159         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
1160                 "_id=? and (itemType=? or itemType=?)",                                                  
1161                 new String[] { String.valueOf(id),                                                       
1162                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
1163                                                                                                          
1164         try {                                                                                            
1165             if (c.moveToFirst()) {                                                                       
1166                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
1167                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
1168                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
1169                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
1170                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
1171                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
1172                                                                                                          
1173                 FolderInfo folderInfo = null;                                                            
1174                 switch (c.getInt(itemTypeIndex)) {                                                       
1175                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
1176                         folderInfo = findOrMakeFolder(folderList, id);                                   
1177                         break;                                                                           
1178                 }                                                                                        
1179                                                                                                          
1180                 folderInfo.title = c.getString(titleIndex);                                              
1181                 folderInfo.id = id;                                                                      
1182                 folderInfo.container = c.getInt(containerIndex);                                         
1183                 folderInfo.screenId = c.getInt(screenIndex);                                             
1184                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
1185                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
1186                                                                                                          
1187                 return folderInfo;                                                                       
1188             }                                                                                            
1189         } finally {                                                                                      
1190             c.close();                                                                                   
1191         }                                                                                                
1192                                                                                                          
1193         return null;                                                                                     
1194     }                                                                                                    
1195                                                                                                          
1196     /**                                                                                                  
1197      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
1198      * cellY fields of the item. Also assigns an ID to the item.                                         
1199      */                                                                                                  
1200     static void addItemToDatabase(Context context, final ItemInfo item, final long container,            
1201             final long screenId, final int cellX, final int cellY, final boolean notify) {               
1202         item.container = container;                                                                      
1203         item.cellX = cellX;                                                                              
1204         item.cellY = cellY;                                                                              
1205         // We store hotseat items in canonical form which is this orientation invariant position         
1206         // in the hotseat                                                                                
1207         if (context instanceof Launcher && screenId < 0 &&                                               
1208                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
1209             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
1210         } else {                                                                                         
1211             item.screenId = screenId;                                                                    
1212         }                                                                                                
1213                                                                                                          
1214         final ContentValues values = new ContentValues();                                                
1215         final ContentResolver cr = context.getContentResolver();                                         
1216         item.onAddToDatabase(values);                                                                    
1217                                                                                                          
1218         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
1219         values.put(LauncherSettings.Favorites._ID, item.id);                                             
1220         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                
1221                                                                                                          
1222         Runnable r = new Runnable() {                                                                    
1223             public void run() {                                                                          
1224                 cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                              
1225                         LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                 
1226                                                                                                          
1227                 // Lock on mBgLock *after* the db operation                                              
1228                 synchronized (sBgLock) {                                                                 
1229                     checkItemInfoLocked(item.id, item, null);                                            
1230                     sBgItemsIdMap.put(item.id, item);                                                    
1231                     switch (item.itemType) {                                                             
1232                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1233                             sBgFolders.put(item.id, (FolderInfo) item);                                  
1234                             // Fall through                                                              
1235                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1236                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1237                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
1238                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
1239                                 sBgWorkspaceItems.add(item);                                             
1240                             } else {                                                                     
1241                                 if (!sBgFolders.containsKey(item.container)) {                           
1242                                     // Adding an item to a folder that doesn't exist.                    
1243                                     String msg = "adding item: " + item + " to a folder that " +         
1244                                             " doesn't exist";                                            
1245                                     Log.e(TAG, msg);                                                     
1246                                 }                                                                        
1247                             }                                                                            
1248                             break;                                                                       
1249                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1250                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
1251                             break;                                                                       
1252                     }                                                                                    
1253                 }                                                                                        
1254             }                                                                                            
1255         };                                                                                               
1256         runOnWorkerThread(r);                                                                            
1257     }                                                                                                    
1258                                                                                                          
1259     /**                                                                                                  
1260      * Creates a new unique child id, for a given cell span across all layouts.                          
1261      */                                                                                                  
1262     static int getCellLayoutChildId(                                                                     
1263             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
1264         return (((int) container & 0xFF) << 24)                                                          
1265                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
1266     }                                                                                                    
1267                                                                                                          
1268     /**                                                                                                  
1269      * Removes the specified item from the database                                                      
1270      * @param context                                                                                    
1271      * @param item                                                                                       
1272      */                                                                                                  
1273     static void deleteItemFromDatabase(Context context, final ItemInfo item) {                           
1274         final ContentResolver cr = context.getContentResolver();                                         
1275         final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);                
1276                                                                                                          
1277         Runnable r = new Runnable() {                                                                    
1278             public void run() {                                                                          
1279                 cr.delete(uriToDelete, null, null);                                                      
1280                                                                                                          
1281                 // Lock on mBgLock *after* the db operation                                              
1282                 synchronized (sBgLock) {                                                                 
1283                     switch (item.itemType) {                                                             
1284                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
1285                             sBgFolders.remove(item.id);                                                  
1286                             for (ItemInfo info: sBgItemsIdMap.values()) {                                
1287                                 if (info.container == item.id) {                                         
1288                                     // We are deleting a folder which still contains items that          
1289                                     // think they are contained by that folder.                          
1290                                     String msg = "deleting a folder (" + item + ") which still " +       
1291                                             "contains items (" + info + ")";                             
1292                                     Log.e(TAG, msg);                                                     
1293                                 }                                                                        
1294                             }                                                                            
1295                             sBgWorkspaceItems.remove(item);                                              
1296                             break;                                                                       
1297                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1298                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1299                             sBgWorkspaceItems.remove(item);                                              
1300                             break;                                                                       
1301                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1302                             sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                          
1303                             break;                                                                       
1304                     }                                                                                    
1305                     sBgItemsIdMap.remove(item.id);                                                       
1306                     sBgDbIconCache.remove(item);                                                         
1307                 }                                                                                        
1308             }                                                                                            
1309         };                                                                                               
1310         runOnWorkerThread(r);                                                                            
1311     }                                                                                                    
1312                                                                                                          
1313     /**                                                                                                  
1314      * Update the order of the workspace screens in the database. The array list contains                
1315      * a list of screen ids in the order that they should appear.                                        
1316      */                                                                                                  
1317     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1318         // Log to disk                                                                                   
1319         Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                       
1320         Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);        
1321                                                                                                          
1322         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1323         final ContentResolver cr = context.getContentResolver();                                         
1324         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1325                                                                                                          
1326         // Remove any negative screen ids -- these aren't persisted                                      
1327         Iterator<Long> iter = screensCopy.iterator();                                                    
1328         while (iter.hasNext()) {                                                                         
1329             long id = iter.next();                                                                       
1330             if (id < 0) {                                                                                
1331                 iter.remove();                                                                           
1332             }                                                                                            
1333         }                                                                                                
1334                                                                                                          
1335         Runnable r = new Runnable() {                                                                    
1336             @Override                                                                                    
1337             public void run() {                                                                          
1338                 // Clear the table                                                                       
1339                 cr.delete(uri, null, null);                                                              
1340                 int count = screensCopy.size();                                                          
1341                 ContentValues[] values = new ContentValues[count];                                       
1342                 for (int i = 0; i < count; i++) {                                                        
1343                     ContentValues v = new ContentValues();                                               
1344                     long screenId = screensCopy.get(i);                                                  
1345                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1346                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1347                     values[i] = v;                                                                       
1348                 }                                                                                        
1349                 cr.bulkInsert(uri, values);                                                              
1350                                                                                                          
1351                 synchronized (sBgLock) {                                                                 
1352                     sBgWorkspaceScreens.clear();                                                         
1353                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1354                 }                                                                                        
1355             }                                                                                            
1356         };                                                                                               
1357         runOnWorkerThread(r);                                                                            
1358     }                                                                                                    
1359                                                                                                          
1360     /**                                                                                                  
1361      * Remove the contents of the specified folder from the database                                     
1362      */                                                                                                  
1363     static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {               
1364         final ContentResolver cr = context.getContentResolver();                                         
1365                                                                                                          
1366         Runnable r = new Runnable() {                                                                    
1367             public void run() {                                                                          
1368                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);         
1369                 // Lock on mBgLock *after* the db operation                                              
1370                 synchronized (sBgLock) {                                                                 
1371                     sBgItemsIdMap.remove(info.id);                                                       
1372                     sBgFolders.remove(info.id);                                                          
1373                     sBgDbIconCache.remove(info);                                                         
1374                     sBgWorkspaceItems.remove(info);                                                      
1375                 }                                                                                        
1376                                                                                                          
1377                 cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                        
1378                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                     
1379                 // Lock on mBgLock *after* the db operation                                              
1380                 synchronized (sBgLock) {                                                                 
1381                     for (ItemInfo childInfo : info.contents) {                                           
1382                         sBgItemsIdMap.remove(childInfo.id);                                              
1383                         sBgDbIconCache.remove(childInfo);                                                
1384                     }                                                                                    
1385                 }                                                                                        
1386             }                                                                                            
1387         };                                                                                               
1388         runOnWorkerThread(r);                                                                            
1389     }                                                                                                    
1390                                                                                                          
1391     /**                                                                                                  
1392      * Set this as the current Launcher activity object for the loader.                                  
1393      */                                                                                                  
1394     public void initialize(Callbacks callbacks) {                                                        
1395         synchronized (mLock) {                                                                           
1396             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1397         }                                                                                                
1398     }                                                                                                    
1399                                                                                                          
1400     /**                                                                                                  
1401      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1402      * ACTION_PACKAGE_CHANGED.                                                                           
1403      */                                                                                                  
1404     @Override                                                                                            
1405     public void onReceive(Context context, Intent intent) {                                              
1406         if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);                                     
1407                                                                                                          
1408         final String action = intent.getAction();                                                        
1409                                                                                                          
1410         if (Intent.ACTION_PACKAGE_CHANGED.equals(action)                                                 
1411                 || Intent.ACTION_PACKAGE_REMOVED.equals(action)                                          
1412                 || Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                         
1413             final String packageName = intent.getData().getSchemeSpecificPart();                         
1414             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1415                                                                                                          
1416             int op = PackageUpdatedTask.OP_NONE;                                                         
1417                                                                                                          
1418             if (packageName == null || packageName.length() == 0) {                                      
1419                 // they sent us a bad intent                                                             
1420                 return;                                                                                  
1421             }                                                                                            
1422                                                                                                          
1423             if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {                                          
1424                 op = PackageUpdatedTask.OP_UPDATE;                                                       
1425             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {                                   
1426                 if (!replacing) {                                                                        
1427                     op = PackageUpdatedTask.OP_REMOVE;                                                   
1428                 }                                                                                        
1429                 // else, we are replacing the package, so a PACKAGE_ADDED will be sent                   
1430                 // later, we will update the package at this time                                        
1431             } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                     
1432                 if (!replacing) {                                                                        
1433                     op = PackageUpdatedTask.OP_ADD;                                                      
1434                 } else {                                                                                 
1435                     op = PackageUpdatedTask.OP_UPDATE;                                                   
1436                 }                                                                                        
1437             }                                                                                            
1438                                                                                                          
1439             if (op != PackageUpdatedTask.OP_NONE) {                                                      
1440                 enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));         
1441             }                                                                                            
1442                                                                                                          
1443         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {                       
1444             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1445             String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);           
1446             if (!replacing) {                                                                            
1447                 enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));      
1448                 if (mAppsCanBeOnRemoveableStorage) {                                                     
1449                     // Only rebind if we support removable storage.  It catches the case where           
1450                     // apps on the external sd card need to be reloaded                                  
1451                     startLoaderFromBackground();                                                         
1452                 }                                                                                        
1453             } else {                                                                                     
1454                 // If we are replacing then just update the packages in the list                         
1455                 enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,               
1456                         packages));                                                                      
1457             }                                                                                            
1458         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {                     
1459             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1460             if (!replacing) {                                                                            
1461                 String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);       
1462                 enqueuePackageUpdated(new PackageUpdatedTask(                                            
1463                             PackageUpdatedTask.OP_UNAVAILABLE, packages));                               
1464             }                                                                                            
1465             // else, we are replacing the packages, so ignore this event and wait for                    
1466             // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time                       
1467         } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                        
1468             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1469             forceReload();                                                                               
1470         } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                 
1471              // Check if configuration change was an mcc/mnc change which would affect app resources     
1472              // and we would need to clear out the labels in all apps/workspace. Same handling as        
1473              // above for ACTION_LOCALE_CHANGED                                                          
1474              Configuration currentConfig = context.getResources().getConfiguration();                    
1475              if (mPreviousConfigMcc != currentConfig.mcc) {                                              
1476                    Log.d(TAG, "Reload apps on config change. curr_mcc:"                                  
1477                        + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                          
1478                    forceReload();                                                                        
1479              }                                                                                           
1480              // Update previousConfig                                                                    
1481              mPreviousConfigMcc = currentConfig.mcc;                                                     
1482         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1483                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1484             if (mCallbacks != null) {                                                                    
1485                 Callbacks callbacks = mCallbacks.get();                                                  
1486                 if (callbacks != null) {                                                                 
1487                     callbacks.bindSearchablesChanged();                                                  
1488                 }                                                                                        
1489             }                                                                                            
1490         }                                                                                                
1491     }                                                                                                    
1492                                                                                                          
1493     private void forceReload() {                                                                         
1494         resetLoadedState(true, true);                                                                    
1495                                                                                                          
1496         // Do this here because if the launcher activity is running it will be restarted.                
1497         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1498         // to reload.                                                                                    
1499         startLoaderFromBackground();                                                                     
1500     }                                                                                                    
1501                                                                                                          
1502     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1503         synchronized (mLock) {                                                                           
1504             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1505             // mWorkspaceLoaded to true later                                                            
1506             stopLoaderLocked();                                                                          
1507             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1508             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1509         }                                                                                                
1510     }                                                                                                    
1511                                                                                                          
1512     /**                                                                                                  
1513      * When the launcher is in the background, it's possible for it to miss paired                       
1514      * configuration changes.  So whenever we trigger the loader from the background                     
1515      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1516      * of doing it now.                                                                                  
1517      */                                                                                                  
1518     public void startLoaderFromBackground() {                                                            
1519         boolean runLoader = false;                                                                       
1520         if (mCallbacks != null) {                                                                        
1521             Callbacks callbacks = mCallbacks.get();                                                      
1522             if (callbacks != null) {                                                                     
1523                 // Only actually run the loader if they're not paused.                                   
1524                 if (!callbacks.setLoadOnResume()) {                                                      
1525                     runLoader = true;                                                                    
1526                 }                                                                                        
1527             }                                                                                            
1528         }                                                                                                
1529         if (runLoader) {                                                                                 
1530             startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                          
1531         }                                                                                                
1532     }                                                                                                    
1533                                                                                                          
1534     // If there is already a loader task running, tell it to stop.                                       
1535     // returns true if isLaunching() was true on the old task                                            
1536     private boolean stopLoaderLocked() {                                                                 
1537         boolean isLaunching = false;                                                                     
1538         LoaderTask oldTask = mLoaderTask;                                                                
1539         if (oldTask != null) {                                                                           
1540             if (oldTask.isLaunching()) {                                                                 
1541                 isLaunching = true;                                                                      
1542             }                                                                                            
1543             oldTask.stopLocked();                                                                        
1544         }                                                                                                
1545         return isLaunching;                                                                              
1546     }                                                                                                    
1547                                                                                                          
1548     public void startLoader(boolean isLaunching, int synchronousBindPage) {                              
1549         startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                 
1550     }                                                                                                    
1551                                                                                                          
1552     public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {               
1553         synchronized (mLock) {                                                                           
1554             if (DEBUG_LOADERS) {                                                                         
1555                 Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                    
1556             }                                                                                            
1557                                                                                                          
1558             // Clear any deferred bind-runnables from the synchronized load process                      
1559             // We must do this before any loading/binding is scheduled below.                            
1560             mDeferredBindRunnables.clear();                                                              
1561                                                                                                          
1562             // Don't bother to start the thread if we know it's not going to do anything                 
1563             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1564                 // If there is already one running, tell it to stop.                                     
1565                 // also, don't downgrade isLaunching if we're already running                            
1566                 isLaunching = isLaunching || stopLoaderLocked();                                         
1567                 mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                 
1568                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1569                         && mAllAppsLoaded && mWorkspaceLoaded) {                                         
1570                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1571                 } else {                                                                                 
1572                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1573                     sWorker.post(mLoaderTask);                                                           
1574                 }                                                                                        
1575             }                                                                                            
1576         }                                                                                                
1577     }                                                                                                    
1578                                                                                                          
1579     void bindRemainingSynchronousPages() {                                                               
1580         // Post the remaining side pages to be loaded                                                    
1581         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1582             for (final Runnable r : mDeferredBindRunnables) {                                            
1583                 mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                          
1584             }                                                                                            
1585             mDeferredBindRunnables.clear();                                                              
1586         }                                                                                                
1587     }                                                                                                    
1588                                                                                                          
1589     public void stopLoader() {                                                                           
1590         synchronized (mLock) {                                                                           
1591             if (mLoaderTask != null) {                                                                   
1592                 mLoaderTask.stopLocked();                                                                
1593             }                                                                                            
1594         }                                                                                                
1595     }                                                                                                    
1596                                                                                                          
1597     /** Loads the workspace screens db into a map of Rank -> ScreenId */                                 
1598     private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {                      
1599         final ContentResolver contentResolver = context.getContentResolver();                            
1600         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1601         final Cursor sc = contentResolver.query(screensUri, null, null, null, null);                     
1602         TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();                            
1603                                                                                                          
1604         try {                                                                                            
1605             final int idIndex = sc.getColumnIndexOrThrow(                                                
1606                     LauncherSettings.WorkspaceScreens._ID);                                              
1607             final int rankIndex = sc.getColumnIndexOrThrow(                                              
1608                     LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                      
1609             while (sc.moveToNext()) {                                                                    
1610                 try {                                                                                    
1611                     long screenId = sc.getLong(idIndex);                                                 
1612                     int rank = sc.getInt(rankIndex);                                                     
1613                     orderedScreens.put(rank, screenId);                                                  
1614                 } catch (Exception e) {                                                                  
1615                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e,🔵
1616                 }                                                                                        
1617             }                                                                                            
1618         } finally {                                                                                      
1619             sc.close();                                                                                  
1620         }                                                                                                
1621                                                                                                          
1622         // Log to disk                                                                                   
1623         Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);                           
1624         ArrayList<String> orderedScreensPairs= new ArrayList<String>();                                  
1625         for (Integer i : orderedScreens.keySet()) {                                                      
1626             orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");                     
1627         }                                                                                                
1628         Launcher.addDumpLog(TAG, "11683562 -   screens: " +                                              
1629                 TextUtils.join(", ", orderedScreensPairs), true);                                        
1630         return orderedScreens;                                                                           
1631     }                                                                                                    
1632                                                                                                          
1633     public boolean isAllAppsLoaded() {                                                                   
1634         return mAllAppsLoaded;                                                                           
1635     }                                                                                                    
1636                                                                                                          
1637     boolean isLoadingWorkspace() {                                                                       
1638         synchronized (mLock) {                                                                           
1639             if (mLoaderTask != null) {                                                                   
1640                 return mLoaderTask.isLoadingWorkspace();                                                 
1641             }                                                                                            
1642         }                                                                                                
1643         return false;                                                                                    
1644     }                                                                                                    
1645                                                                                                          
1646     /**                                                                                                  
1647      * Runnable for the thread that loads the contents of the launcher:                                  
1648      *   - workspace icons                                                                               
1649      *   - widgets                                                                                       
1650      *   - all apps icons                                                                                
1651      */                                                                                                  
1652     private class LoaderTask implements Runnable {                                                       
1653         private Context mContext;                                                                        
1654         private boolean mIsLaunching;                                                                    
1655         private boolean mIsLoadingAndBindingWorkspace;                                                   
1656         private boolean mStopped;                                                                        
1657         private boolean mLoadAndBindStepFinished;                                                        
1658         private int mFlags;                                                                              
1659                                                                                                          
1660         private HashMap<Object, CharSequence> mLabelCache;                                               
1661                                                                                                          
1662         LoaderTask(Context context, boolean isLaunching, int flags) {                                    
1663             mContext = context;                                                                          
1664             mIsLaunching = isLaunching;                                                                  
1665             mLabelCache = new HashMap<Object, CharSequence>();                                           
1666             mFlags = flags;                                                                              
1667         }                                                                                                
1668                                                                                                          
1669         boolean isLaunching() {                                                                          
1670             return mIsLaunching;                                                                         
1671         }                                                                                                
1672                                                                                                          
1673         boolean isLoadingWorkspace() {                                                                   
1674             return mIsLoadingAndBindingWorkspace;                                                        
1675         }                                                                                                
1676                                                                                                          
1677         /** Returns whether this is an upgrade path */                                                   
1678         private boolean loadAndBindWorkspace() {                                                         
1679             mIsLoadingAndBindingWorkspace = true;                                                        
1680                                                                                                          
1681             // Load the workspace                                                                        
1682             if (DEBUG_LOADERS) {                                                                         
1683                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1684             }                                                                                            
1685                                                                                                          
1686             boolean isUpgradePath = false;                                                               
1687             if (!mWorkspaceLoaded) {                                                                     
1688                 isUpgradePath = loadWorkspace();                                                         
1689                 synchronized (LoaderTask.this) {                                                         
1690                     if (mStopped) {                                                                      
1691                         return isUpgradePath;                                                            
1692                     }                                                                                    
1693                     mWorkspaceLoaded = true;                                                             
1694                 }                                                                                        
1695             }                                                                                            
1696                                                                                                          
1697             // Bind the workspace                                                                        
1698             bindWorkspace(-1, isUpgradePath);                                                            
1699             return isUpgradePath;                                                                        
1700         }                                                                                                
1701                                                                                                          
1702         private void waitForIdle() {                                                                     
1703             // Wait until the either we're stopped or the other threads are done.                        
1704             // This way we don't start loading all apps until the workspace has settled                  
1705             // down.                                                                                     
1706             synchronized (LoaderTask.this) {                                                             
1707                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1708                                                                                                          
1709                 mHandler.postIdle(new Runnable() {                                                       
1710                         public void run() {                                                              
1711                             synchronized (LoaderTask.this) {                                             
1712                                 mLoadAndBindStepFinished = true;                                         
1713                                 if (DEBUG_LOADERS) {                                                     
1714                                     Log.d(TAG, "done with previous binding step");                       
1715                                 }                                                                        
1716                                 LoaderTask.this.notify();                                                
1717                             }                                                                            
1718                         }                                                                                
1719                     });                                                                                  
1720                                                                                                          
1721                 while (!mStopped && !mLoadAndBindStepFinished && !mFlushingWorkerThread) {               
1722                     try {                                                                                
1723                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1724                         // wait no longer than 1sec at a time                                            
1725                         this.wait(1000);                                                                 
1726                     } catch (InterruptedException ex) {                                                  
1727                         // Ignore                                                                        
1728                     }                                                                                    
1729                 }                                                                                        
1730                 if (DEBUG_LOADERS) {                                                                     
1731                     Log.d(TAG, "waited "                                                                 
1732                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1733                             + "ms for previous step to finish binding");                                 
1734                 }                                                                                        
1735             }                                                                                            
1736         }                                                                                                
1737                                                                                                          
1738         void runBindSynchronousPage(int synchronousBindPage) {                                           
1739             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1740                 // Ensure that we have a valid page index to load synchronously                          
1741                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1742                         "valid page index");                                                             
1743             }                                                                                            
1744             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1745                 // Ensure that we don't try and bind a specified page when the pages have not been       
1746                 // loaded already (we should load everything asynchronously in that case)                
1747                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1748             }                                                                                            
1749             synchronized (mLock) {                                                                       
1750                 if (mIsLoaderTaskRunning) {                                                              
1751                     // Ensure that we are never running the background loading at this point since       
1752                     // we also touch the background collections                                          
1753                     throw new RuntimeException("Error! Background loading is already running");          
1754                 }                                                                                        
1755             }                                                                                            
1756                                                                                                          
1757             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1758             //      data structures, we can't allow any other thread to touch that data, but because     
1759             //      this call is synchronous, we can get away with not locking).                         
1760                                                                                                          
1761             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1762             // operations from the previous activity.  We need to ensure that all queued operations      
1763             // are executed before any synchronous binding work is done.                                 
1764             mHandler.flush();                                                                            
1765                                                                                                          
1766             // Divide the set of loaded items into those that we are binding synchronously, and          
1767             // everything else that is to be bound normally (asynchronously).                            
1768             bindWorkspace(synchronousBindPage, false);                                                   
1769             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1770             //      arise from that.                                                                     
1771             onlyBindAllApps();                                                                           
1772         }                                                                                                
1773                                                                                                          
1774         public void run() {                                                                              
1775             boolean isUpgrade = false;                                                                   
1776                                                                                                          
1777             synchronized (mLock) {                                                                       
1778                 mIsLoaderTaskRunning = true;                                                             
1779             }                                                                                            
1780             // Optimize for end-user experience: if the Launcher is up and // running with the           
1781             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1782             // workspace first (default).                                                                
1783             keep_running: {                                                                              
1784                 // Elevate priority when Home launches for the first time to avoid                       
1785                 // starving at boot time. Staring at a blank home is not cool.                           
1786                 synchronized (mLock) {                                                                   
1787                     if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                        
1788                             (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                  
1789                     android.os.Process.setThreadPriority(mIsLaunching                                    
1790                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);     
1791                 }                                                                                        
1792                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1793                 isUpgrade = loadAndBindWorkspace();                                                      
1794                                                                                                          
1795                 if (mStopped) {                                                                          
1796                     break keep_running;                                                                  
1797                 }                                                                                        
1798                                                                                                          
1799                 // Whew! Hard work done.  Slow us down, and wait until the UI thread has                 
1800                 // settled down.                                                                         
1801                 synchronized (mLock) {                                                                   
1802                     if (mIsLaunching) {                                                                  
1803                         if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");          
1804                         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        
1805                     }                                                                                    
1806                 }                                                                                        
1807                 waitForIdle();                                                                           
1808                                                                                                          
1809                 // second step                                                                           
1810                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1811                 loadAndBindAllApps();                                                                    
1812                                                                                                          
1813                 // Restore the default thread priority after we are done loading items                   
1814                 synchronized (mLock) {                                                                   
1815                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);               
1816                 }                                                                                        
1817             }                                                                                            
1818                                                                                                          
1819             // Update the saved icons if necessary                                                       
1820             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1821             synchronized (sBgLock) {                                                                     
1822                 for (Object key : sBgDbIconCache.keySet()) {                                             
1823                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1824                 }                                                                                        
1825                 sBgDbIconCache.clear();                                                                  
1826             }                                                                                            
1827                                                                                                          
1828             if (LauncherAppState.isDisableAllApps()) {                                                   
1829                 // Ensure that all the applications that are in the system are                           
1830                 // represented on the home screen.                                                       
1831                 if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {                                       
1832                     verifyApplications();                                                                
1833                 }                                                                                        
1834             }                                                                                            
1835                                                                                                          
1836             // Clear out this reference, otherwise we end up holding it until all of the                 
1837             // callback runnables are done.                                                              
1838             mContext = null;                                                                             
1839                                                                                                          
1840             synchronized (mLock) {                                                                       
1841                 // If we are still the last one to be scheduled, remove ourselves.                       
1842                 if (mLoaderTask == this) {                                                               
1843                     mLoaderTask = null;                                                                  
1844                 }                                                                                        
1845                 mIsLoaderTaskRunning = false;                                                            
1846             }                                                                                            
1847         }                                                                                                
1848                                                                                                          
1849         public void stopLocked() {                                                                       
1850             synchronized (LoaderTask.this) {                                                             
1851                 mStopped = true;                                                                         
1852                 this.notify();                                                                           
1853             }                                                                                            
1854         }                                                                                                
1855                                                                                                          
1856         /**                                                                                              
1857          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1858          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1859          * object that was around when the deferred message was scheduled, and if there's                
1860          * a new Callbacks object around then also return null.  This will save us from                  
1861          * calling onto it with data that will be ignored.                                               
1862          */                                                                                              
1863         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1864             synchronized (mLock) {                                                                       
1865                 if (mStopped) {                                                                          
1866                     return null;                                                                         
1867                 }                                                                                        
1868                                                                                                          
1869                 if (mCallbacks == null) {                                                                
1870                     return null;                                                                         
1871                 }                                                                                        
1872                                                                                                          
1873                 final Callbacks callbacks = mCallbacks.get();                                            
1874                 if (callbacks != oldCallbacks) {                                                         
1875                     return null;                                                                         
1876                 }                                                                                        
1877                 if (callbacks == null) {                                                                 
1878                     Log.w(TAG, "no mCallbacks");                                                         
1879                     return null;                                                                         
1880                 }                                                                                        
1881                                                                                                          
1882                 return callbacks;                                                                        
1883             }                                                                                            
1884         }                                                                                                
1885                                                                                                          
1886         private void verifyApplications() {                                                              
1887             final Context context = mApp.getContext();                                                   
1888                                                                                                          
1889             // Cross reference all the applications in our apps list with items in the workspace         
1890             ArrayList<ItemInfo> tmpInfos;                                                                
1891             ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                       
1892             synchronized (sBgLock) {                                                                     
1893                 for (AppInfo app : mBgAllAppsList.data) {                                                
1894                     tmpInfos = getItemInfoForComponentName(app.componentName);                           
1895                     if (tmpInfos.isEmpty()) {                                                            
1896                         // We are missing an application icon, so add this to the workspace              
1897                         added.add(app);                                                                  
1898                         // This is a rare event, so lets log it                                          
1899                         Log.e(TAG, "Missing Application on load: " + app);                               
1900                     }                                                                                    
1901                 }                                                                                        
1902             }                                                                                            
1903             if (!added.isEmpty()) {                                                                      
1904                 Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                             
1905                 addAndBindAddedApps(context, added, cb, new ArrayList<AppInfo>());                       
1906             }                                                                                            
1907         }                                                                                                
1908                                                                                                          
1909         // check & update map of what's occupied; used to discard overlapping/invalid items              
1910         private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item,          
1911                                            AtomicBoolean deleteOnInvalidPlacement) {                     
1912             LauncherAppState app = LauncherAppState.getInstance();                                       
1913             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1914             final int countX = (int) grid.numColumns;                                                    
1915             final int countY = (int) grid.numRows;                                                       
1916                                                                                                          
1917             long containerIndex = item.screenId;                                                         
1918             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1919                 // Return early if we detect that an item is under the hotseat button                    
1920                 if (mCallbacks == null ||                                                                
1921                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1922                     deleteOnInvalidPlacement.set(true);                                                  
1923                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1924                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1925                             + item.cellY + ") occupied by all apps");                                    
1926                     return false;                                                                        
1927                 }                                                                                        
1928                                                                                                          
1929                 final ItemInfo[][] hotseatItems =                                                        
1930                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1931                                                                                                          
1932                 if (item.screenId >= grid.numHotseatIcons) {                                             
1933                     Log.e(TAG, "Error loading shortcut " + item                                          
1934                             + " into hotseat position " + item.screenId                                  
1935                             + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)            
1936                             + ")");                                                                      
1937                     return false;                                                                        
1938                 }                                                                                        
1939                                                                                                          
1940                 if (hotseatItems != null) {                                                              
1941                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1942                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1943                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1944                                 + item.cellY + ") occupied by "                                          
1945                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1946                                 [(int) item.screenId][0]);                                               
1947                             return false;                                                                
1948                     } else {                                                                             
1949                         hotseatItems[(int) item.screenId][0] = item;                                     
1950                         return true;                                                                     
1951                     }                                                                                    
1952                 } else {                                                                                 
1953                     final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];              
1954                     items[(int) item.screenId][0] = item;                                                
1955                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1956                     return true;                                                                         
1957                 }                                                                                        
1958             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1959                 // Skip further checking if it is not the hotseat or workspace container                 
1960                 return true;                                                                             
1961             }                                                                                            
1962                                                                                                          
1963             if (!occupied.containsKey(item.screenId)) {                                                  
1964                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1965                 occupied.put(item.screenId, items);                                                      
1966             }                                                                                            
1967                                                                                                          
1968             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1969             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1970                     item.cellX < 0 || item.cellY < 0 ||                                                  
1971                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1972                 Log.e(TAG, "Error loading shortcut " + item                                              
1973                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1974                         + item.cellX + "," + item.cellY                                                  
1975                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1976                 return false;                                                                            
1977             }                                                                                            
1978                                                                                                          
1979             // Check if any workspace icons overlap with each other                                      
1980             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1981                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1982                     if (screens[x][y] != null) {                                                         
1983                         Log.e(TAG, "Error loading shortcut " + item                                      
1984                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1985                             + x + "," + y                                                                
1986                             + ") occupied by "                                                           
1987                             + screens[x][y]);                                                            
1988                         return false;                                                                    
1989                     }                                                                                    
1990                 }                                                                                        
1991             }                                                                                            
1992             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1993                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1994                     screens[x][y] = item;                                                                
1995                 }                                                                                        
1996             }                                                                                            
1997                                                                                                          
1998             return true;                                                                                 
1999         }                                                                                                
2000                                                                                                          
2001         /** Clears all the sBg data structures */                                                        
2002         private void clearSBgDataStructures() {                                                          
2003             synchronized (sBgLock) {                                                                     
2004                 sBgWorkspaceItems.clear();                                                               
2005                 sBgAppWidgets.clear();                                                                   
2006                 sBgFolders.clear();                                                                      
2007                 sBgItemsIdMap.clear();                                                                   
2008                 sBgDbIconCache.clear();                                                                  
2009                 sBgWorkspaceScreens.clear();                                                             
2010             }                                                                                            
2011         }                                                                                                
2012                                                                                                          
2013         /** Returns whether this is an upgrade path */                                                   
2014         private boolean loadWorkspace() {                                                                
2015             // Log to disk                                                                               
2016             Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                
2017                                                                                                          
2018             final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                               
2019                                                                                                          
2020             final Context context = mContext;                                                            
2021             final ContentResolver contentResolver = context.getContentResolver();                        
2022             final PackageManager manager = context.getPackageManager();                                  
2023             final AppWidgetManager widgets = AppWidgetManager.getInstance(context);                      
2024             final boolean isSafeMode = manager.isSafeMode();                                             
2025                                                                                                          
2026             LauncherAppState app = LauncherAppState.getInstance();                                       
2027             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
2028             int countX = (int) grid.numColumns;                                                          
2029             int countY = (int) grid.numRows;                                                             
2030                                                                                                          
2031             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
2032                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
2033                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
2034             }                                                                                            
2035                                                                                                          
2036             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
2037                 // append the user's Launcher2 shortcuts                                                 
2038                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
2039                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
2040             } else {                                                                                     
2041                 // Make sure the default workspace is loaded                                             
2042                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
2043                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);               
2044             }                                                                                            
2045                                                                                                          
2046             // Check if we need to do any upgrade-path logic                                             
2047             // (Includes having just imported default favorites)                                         
2048             boolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb();              
2049                                                                                                          
2050             // Log to disk                                                                               
2051             Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);                  
2052                                                                                                          
2053             synchronized (sBgLock) {                                                                     
2054                 clearSBgDataStructures();                                                                
2055                                                                                                          
2056                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
2057                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
2058                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                           
2059                 if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                       
2060                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
2061                                                                                                          
2062                 // +1 for the hotseat (it can be larger than the workspace)                              
2063                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
2064                 // before any earlier duplicates)                                                        
2065                 final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();          
2066                                                                                                          
2067                 try {                                                                                    
2068                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
2069                     final int intentIndex = c.getColumnIndexOrThrow                                      
2070                             (LauncherSettings.Favorites.INTENT);                                         
2071                     final int titleIndex = c.getColumnIndexOrThrow                                       
2072                             (LauncherSettings.Favorites.TITLE);                                          
2073                     final int iconTypeIndex = c.getColumnIndexOrThrow(                                   
2074                             LauncherSettings.Favorites.ICON_TYPE);                                       
2075                     final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);      
2076                     final int iconPackageIndex = c.getColumnIndexOrThrow(                                
2077                             LauncherSettings.Favorites.ICON_PACKAGE);                                    
2078                     final int iconResourceIndex = c.getColumnIndexOrThrow(                               
2079                             LauncherSettings.Favorites.ICON_RESOURCE);                                   
2080                     final int containerIndex = c.getColumnIndexOrThrow(                                  
2081                             LauncherSettings.Favorites.CONTAINER);                                       
2082                     final int itemTypeIndex = c.getColumnIndexOrThrow(                                   
2083                             LauncherSettings.Favorites.ITEM_TYPE);                                       
2084                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                
2085                             LauncherSettings.Favorites.APPWIDGET_ID);                                    
2086                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                          
2087                             LauncherSettings.Favorites.APPWIDGET_PROVIDER);                              
2088                     final int screenIndex = c.getColumnIndexOrThrow(                                     
2089                             LauncherSettings.Favorites.SCREEN);                                          
2090                     final int cellXIndex = c.getColumnIndexOrThrow                                       
2091                             (LauncherSettings.Favorites.CELLX);                                          
2092                     final int cellYIndex = c.getColumnIndexOrThrow                                       
2093                             (LauncherSettings.Favorites.CELLY);                                          
2094                     final int spanXIndex = c.getColumnIndexOrThrow                                       
2095                             (LauncherSettings.Favorites.SPANX);                                          
2096                     final int spanYIndex = c.getColumnIndexOrThrow(                                      
2097                             LauncherSettings.Favorites.SPANY);                                           
2098                     final int restoredIndex = c.getColumnIndexOrThrow(                                   
2099                             LauncherSettings.Favorites.RESTORED);                                        
2100                     //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);      
2101                     //final int displayModeIndex = c.getColumnIndexOrThrow(                              
2102                     //        LauncherSettings.Favorites.DISPLAY_MODE);                                  
2103                                                                                                          
2104                     ShortcutInfo info;                                                                   
2105                     String intentDescription;                                                            
2106                     LauncherAppWidgetInfo appWidgetInfo;                                                 
2107                     int container;                                                                       
2108                     long id;                                                                             
2109                     Intent intent;                                                                       
2110                                                                                                          
2111                     while (!mStopped && c.moveToNext()) {                                                
2112                         AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);               
2113                         try {                                                                            
2114                             int itemType = c.getInt(itemTypeIndex);                                      
2115                             boolean restored = 0 != c.getInt(restoredIndex);                             
2116                                                                                                          
2117                             switch (itemType) {                                                          
2118                             case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                       
2119                             case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                          
2120                                 id = c.getLong(idIndex);                                                 
2121                                 intentDescription = c.getString(intentIndex);                            
2122                                 try {                                                                    
2123                                     intent = Intent.parseUri(intentDescription, 0);                      
2124                                     ComponentName cn = intent.getComponent();                            
2125                                     if (cn != null && !isValidPackageComponent(manager, cn)) {           
2126                                         if (restored) {                                                  
2127                                             // might be installed later                                  
2128                                             Launcher.addDumpLog(TAG,                                     
2129                                                     "package not yet restored: " + cn, true);            
2130                                         } else {                                                         
2131                                             if (!mAppsCanBeOnRemoveableStorage) {                        
2132                                                 // Log the invalid package, and remove it                
2133                                                 Launcher.addDumpLog(TAG,                                 
2134                                                         "Invalid package removed: " + cn, true);         
2135                                                 itemsToRemove.add(id);                                   
2136                                             } else {                                                     
2137                                                 // If apps can be on external storage, then we just      
2138                                                 // leave them for the user to remove (maybe add          
2139                                                 // visual treatment to it)                               
2140                                                 Launcher.addDumpLog(TAG,                                 
2141                                                         "Invalid package found: " + cn, true);           
2142                                             }                                                            
2143                                             continue;                                                    
2144                                         }                                                                
2145                                     } else if (restored) {                                               
2146                                         // no special handling necessary for this restored item          
2147                                         restoredRows.add(id);                                            
2148                                         restored = false;                                                
2149                                     }                                                                    
2150                                 } catch (URISyntaxException e) {                                         
2151                                     Launcher.addDumpLog(TAG,                                             
2152                                             "Invalid uri: " + intentDescription, true);                  
2153                                     continue;                                                            
2154                                 }                                                                        
2155                                                                                                          
2156                                 if (restored) {                                                          
2157                                     Launcher.addDumpLog(TAG,                                             
2158                                             "constructing info for partially restored package",          
2159                                             true);                                                       
2160                                     info = getRestoredItemInfo(c, titleIndex, intent);                   
2161                                     intent = getRestoredItemIntent(c, context, intent);                  
2162                                 } else if (itemType ==                                                   
2163                                         LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {              
2164                                     info = getShortcutInfo(manager, intent, context, c, iconIndex,       
2165                                             titleIndex, mLabelCache);                                    
2166                                 } else {                                                                 
2167                                     info = getShortcutInfo(c, context, iconTypeIndex,                    
2168                                             iconPackageIndex, iconResourceIndex, iconIndex,              
2169                                             titleIndex);                                                 
2170                                                                                                          
2171                                     // App shortcuts that used to be automatically added to Launcher     
2172                                     // didn't always have the correct intent flags set, so do that       
2173                                     // here                                                              
2174                                     if (intent.getAction() != null &&                                    
2175                                         intent.getCategories() != null &&                                
2176                                         intent.getAction().equals(Intent.ACTION_MAIN) &&                 
2177                                         intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {     
2178                                         intent.addFlags(                                                 
2179                                             Intent.FLAG_ACTIVITY_NEW_TASK |                              
2180                                             Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                  
2181                                     }                                                                    
2182                                 }                                                                        
2183                                                                                                          
2184                                 if (info != null) {                                                      
2185                                     info.id = id;                                                        
2186                                     info.intent = intent;                                                
2187                                     container = c.getInt(containerIndex);                                
2188                                     info.container = container;                                          
2189                                     info.screenId = c.getInt(screenIndex);                               
2190                                     info.cellX = c.getInt(cellXIndex);                                   
2191                                     info.cellY = c.getInt(cellYIndex);                                   
2192                                     info.spanX = 1;                                                      
2193                                     info.spanY = 1;                                                      
2194                                                                                                          
2195                                     // check & update map of what's occupied                             
2196                                     deleteOnInvalidPlacement.set(false);                                 
2197                                     if (!checkItemPlacement(occupied, info, deleteOnInvalidPlacement)) { 
2198                                         if (deleteOnInvalidPlacement.get()) {                            
2199                                             itemsToRemove.add(id);                                       
2200                                         }                                                                
2201                                         break;                                                           
2202                                     }                                                                    
2203                                                                                                          
2204                                     switch (container) {                                                 
2205                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2206                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2207                                         sBgWorkspaceItems.add(info);                                     
2208                                         break;                                                           
2209                                     default:                                                             
2210                                         // Item is in a user folder                                      
2211                                         FolderInfo folderInfo =                                          
2212                                                 findOrMakeFolder(sBgFolders, container);                 
2213                                         folderInfo.add(info);                                            
2214                                         break;                                                           
2215                                     }                                                                    
2216                                     sBgItemsIdMap.put(info.id, info);                                    
2217                                                                                                          
2218                                     // now that we've loaded everthing re-save it with the               
2219                                     // icon in case it disappears somehow.                               
2220                                     queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);            
2221                                 } else {                                                                 
2222                                     throw new RuntimeException("Unexpected null ShortcutInfo");          
2223                                 }                                                                        
2224                                 break;                                                                   
2225                                                                                                          
2226                             case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                            
2227                                 id = c.getLong(idIndex);                                                 
2228                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                
2229                                                                                                          
2230                                 folderInfo.title = c.getString(titleIndex);                              
2231                                 folderInfo.id = id;                                                      
2232                                 container = c.getInt(containerIndex);                                    
2233                                 folderInfo.container = container;                                        
2234                                 folderInfo.screenId = c.getInt(screenIndex);                             
2235                                 folderInfo.cellX = c.getInt(cellXIndex);                                 
2236                                 folderInfo.cellY = c.getInt(cellYIndex);                                 
2237                                 folderInfo.spanX = 1;                                                    
2238                                 folderInfo.spanY = 1;                                                    
2239                                                                                                          
2240                                 // check & update map of what's occupied                                 
2241                                 deleteOnInvalidPlacement.set(false);                                     
2242                                 if (!checkItemPlacement(occupied, folderInfo,                            
2243                                         deleteOnInvalidPlacement)) {                                     
2244                                     if (deleteOnInvalidPlacement.get()) {                                
2245                                         itemsToRemove.add(id);                                           
2246                                     }                                                                    
2247                                     break;                                                               
2248                                 }                                                                        
2249                                                                                                          
2250                                 switch (container) {                                                     
2251                                     case LauncherSettings.Favorites.CONTAINER_DESKTOP:                   
2252                                     case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                   
2253                                         sBgWorkspaceItems.add(folderInfo);                               
2254                                         break;                                                           
2255                                 }                                                                        
2256                                                                                                          
2257                                 if (restored) {                                                          
2258                                     // no special handling required for restored folders                 
2259                                     restoredRows.add(id);                                                
2260                                 }                                                                        
2261                                                                                                          
2262                                 sBgItemsIdMap.put(folderInfo.id, folderInfo);                            
2263                                 sBgFolders.put(folderInfo.id, folderInfo);                               
2264                                 break;                                                                   
2265                                                                                                          
2266                             case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                         
2267                                 // Read all Launcher-specific widget details                             
2268                                 int appWidgetId = c.getInt(appWidgetIdIndex);                            
2269                                 String savedProvider = c.getString(appWidgetProviderIndex);              
2270                                                                                                          
2271                                 id = c.getLong(idIndex);                                                 
2272                                                                                                          
2273                                 final AppWidgetProviderInfo provider =                                   
2274                                         widgets.getAppWidgetInfo(appWidgetId);                           
2275                                                                                                          
2276                                 if (!isSafeMode && (provider == null || provider.provider == null ||     
2277                                         provider.provider.getPackageName() == null)) {                   
2278                                     String log = "Deleting widget that isn't installed anymore: id="     
2279                                         + id + " appWidgetId=" + appWidgetId;                            
2280                                     Log.e(TAG, log);                                                     
2281                                     Launcher.addDumpLog(TAG, log, false);                                
2282                                     itemsToRemove.add(id);                                               
2283                                 } else {                                                                 
2284                                     appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,               
2285                                             provider.provider);                                          
2286                                     appWidgetInfo.id = id;                                               
2287                                     appWidgetInfo.screenId = c.getInt(screenIndex);                      
2288                                     appWidgetInfo.cellX = c.getInt(cellXIndex);                          
2289                                     appWidgetInfo.cellY = c.getInt(cellYIndex);                          
2290                                     appWidgetInfo.spanX = c.getInt(spanXIndex);                          
2291                                     appWidgetInfo.spanY = c.getInt(spanYIndex);                          
2292                                     int[] minSpan = Launcher.getMinSpanForWidget(context, provider);     
2293                                     appWidgetInfo.minSpanX = minSpan[0];                                 
2294                                     appWidgetInfo.minSpanY = minSpan[1];                                 
2295                                                                                                          
2296                                     container = c.getInt(containerIndex);                                
2297                                     if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&     
2298                                         container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {     
2299                                         Log.e(TAG, "Widget found where container != " +                  
2300                                             "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");      
2301                                         continue;                                                        
2302                                     }                                                                    
2303                                                                                                          
2304                                     appWidgetInfo.container = c.getInt(containerIndex);                  
2305                                     // check & update map of what's occupied                             
2306                                     deleteOnInvalidPlacement.set(false);                                 
2307                                     if (!checkItemPlacement(occupied, appWidgetInfo,                     
2308                                             deleteOnInvalidPlacement)) {                                 
2309                                         if (deleteOnInvalidPlacement.get()) {                            
2310                                             itemsToRemove.add(id);                                       
2311                                         }                                                                
2312                                         break;                                                           
2313                                     }                                                                    
2314                                     String providerName = provider.provider.flattenToString();           
2315                                     if (!providerName.equals(savedProvider)) {                           
2316                                         ContentValues values = new ContentValues();                      
2317                                         values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,        
2318                                                 providerName);                                           
2319                                         String where = BaseColumns._ID + "= ?";                          
2320                                         String[] args = {Integer.toString(c.getInt(idIndex))};           
2321                                         contentResolver.update(contentUri, values, where, args);         
2322                                     }                                                                    
2323                                     sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                  
2324                                     sBgAppWidgets.add(appWidgetInfo);                                    
2325                                 }                                                                        
2326                                 break;                                                                   
2327                             }                                                                            
2328                         } catch (Exception e) {                                                          
2329                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
2330                         }                                                                                
2331                     }                                                                                    
2332                 } finally {                                                                              
2333                     if (c != null) {                                                                     
2334                         c.close();                                                                       
2335                     }                                                                                    
2336                 }                                                                                        
2337                                                                                                          
2338                 // Break early if we've stopped loading                                                  
2339                 if (mStopped) {                                                                          
2340                     clearSBgDataStructures();                                                            
2341                     return false;                                                                        
2342                 }                                                                                        
2343                                                                                                          
2344                 if (itemsToRemove.size() > 0) {                                                          
2345                     ContentProviderClient client = contentResolver.acquireContentProviderClient(         
2346                             LauncherSettings.Favorites.CONTENT_URI);                                     
2347                     // Remove dead items                                                                 
2348                     for (long id : itemsToRemove) {                                                      
2349                         if (DEBUG_LOADERS) {                                                             
2350                             Log.d(TAG, "Removed id = " + id);                                            
2351                         }                                                                                
2352                         // Don't notify content observers                                                
2353                         try {                                                                            
2354                             client.delete(LauncherSettings.Favorites.getContentUri(id, false),           
2355                                     null, null);                                                         
2356                         } catch (RemoteException e) {                                                    
2357                             Log.w(TAG, "Could not remove id = " + id);                                   
2358                         }                                                                                
2359                     }                                                                                    
2360                 }                                                                                        
2361                                                                                                          
2362                 if (restoredRows.size() > 0) {                                                           
2363                     ContentProviderClient updater = contentResolver.acquireContentProviderClient(        
2364                             LauncherSettings.Favorites.CONTENT_URI);                                     
2365                     // Update restored items that no longer require special handling                     
2366                     try {                                                                                
2367                         StringBuilder selectionBuilder = new StringBuilder();                            
2368                         selectionBuilder.append(LauncherSettings.Favorites._ID);                         
2369                         selectionBuilder.append(" IN (");                                                
2370                         selectionBuilder.append(TextUtils.join(", ", restoredRows));                     
2371                         selectionBuilder.append(")");                                                    
2372                         ContentValues values = new ContentValues();                                      
2373                         values.put(LauncherSettings.Favorites.RESTORED, 0);                              
2374                         updater.update(LauncherSettings.Favorites.CONTENT_URI,                           
2375                                 values, selectionBuilder.toString(), null);                              
2376                     } catch (RemoteException e) {                                                        
2377                         Log.w(TAG, "Could not update restored rows");                                    
2378                     }                                                                                    
2379                 }                                                                                        
2380                                                                                                          
2381                 if (loadedOldDb) {                                                                       
2382                     long maxScreenId = 0;                                                                
2383                     // If we're importing we use the old screen order.                                   
2384                     for (ItemInfo item: sBgItemsIdMap.values()) {                                        
2385                         long screenId = item.screenId;                                                   
2386                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&            
2387                                 !sBgWorkspaceScreens.contains(screenId)) {                               
2388                             sBgWorkspaceScreens.add(screenId);                                           
2389                             if (screenId > maxScreenId) {                                                
2390                                 maxScreenId = screenId;                                                  
2391                             }                                                                            
2392                         }                                                                                
2393                     }                                                                                    
2394                     Collections.sort(sBgWorkspaceScreens);                                               
2395                     // Log to disk                                                                       
2396                     Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);          
2397                     Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                      
2398                             TextUtils.join(", ", sBgWorkspaceScreens), true);                            
2399                                                                                                          
2400                     LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);               
2401                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2402                                                                                                          
2403                     // Update the max item id after we load an old db                                    
2404                     long maxItemId = 0;                                                                  
2405                     // If we're importing we use the old screen order.                                   
2406                     for (ItemInfo item: sBgItemsIdMap.values()) {                                        
2407                         maxItemId = Math.max(maxItemId, item.id);                                        
2408                     }                                                                                    
2409                     LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);                   
2410                 } else {                                                                                 
2411                     TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);            
2412                     for (Integer i : orderedScreens.keySet()) {                                          
2413                         sBgWorkspaceScreens.add(orderedScreens.get(i));                                  
2414                     }                                                                                    
2415                     // Log to disk                                                                       
2416                     Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                      
2417                             TextUtils.join(", ", sBgWorkspaceScreens), true);                            
2418                                                                                                          
2419                     // Remove any empty screens                                                          
2420                     ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);            
2421                     for (ItemInfo item: sBgItemsIdMap.values()) {                                        
2422                         long screenId = item.screenId;                                                   
2423                         if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&            
2424                                 unusedScreens.contains(screenId)) {                                      
2425                             unusedScreens.remove(screenId);                                              
2426                         }                                                                                
2427                     }                                                                                    
2428                                                                                                          
2429                     // If there are any empty screens remove them, and update.                           
2430                     if (unusedScreens.size() != 0) {                                                     
2431                         // Log to disk                                                                   
2432                         Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +        
2433                                 TextUtils.join(", ", unusedScreens), true);                              
2434                                                                                                          
2435                         sBgWorkspaceScreens.removeAll(unusedScreens);                                    
2436                         updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                        
2437                     }                                                                                    
2438                 }                                                                                        
2439                                                                                                          
2440                 if (DEBUG_LOADERS) {                                                                     
2441                     Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");          
2442                     Log.d(TAG, "workspace layout: ");                                                    
2443                     int nScreens = occupied.size();                                                      
2444                     for (int y = 0; y < countY; y++) {                                                   
2445                         String line = "";                                                                
2446                                                                                                          
2447                         Iterator<Long> iter = occupied.keySet().iterator();                              
2448                         while (iter.hasNext()) {                                                         
2449                             long screenId = iter.next();                                                 
2450                             if (screenId > 0) {                                                          
2451                                 line += " | ";                                                           
2452                             }                                                                            
2453                             for (int x = 0; x < countX; x++) {                                           
2454                                 line += ((occupied.get(screenId)[x][y] != null) ? "#" : ".");            
2455                             }                                                                            
2456                         }                                                                                
2457                         Log.d(TAG, "[ " + line + " ]");                                                  
2458                     }                                                                                    
2459                 }                                                                                        
2460             }                                                                                            
2461             return loadedOldDb;                                                                          
2462         }                                                                                                
2463                                                                                                          
2464         /** Filters the set of items who are directly or indirectly (via another container) on the       
2465          * specified screen. */                                                                          
2466         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2467                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2468                 ArrayList<ItemInfo> currentScreenItems,                                                  
2469                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2470             // Purge any null ItemInfos                                                                  
2471             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2472             while (iter.hasNext()) {                                                                     
2473                 ItemInfo i = iter.next();                                                                
2474                 if (i == null) {                                                                         
2475                     iter.remove();                                                                       
2476                 }                                                                                        
2477             }                                                                                            
2478                                                                                                          
2479             // Order the set of items by their containers first, this allows use to walk through the     
2480             // list sequentially, build up a list of containers that are in the specified screen,        
2481             // as well as all items in those containers.                                                 
2482             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2483             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2484                 @Override                                                                                
2485                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2486                     return (int) (lhs.container - rhs.container);                                        
2487                 }                                                                                        
2488             });                                                                                          
2489             for (ItemInfo info : allWorkspaceItems) {                                                    
2490                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2491                     if (info.screenId == currentScreenId) {                                              
2492                         currentScreenItems.add(info);                                                    
2493                         itemsOnScreen.add(info.id);                                                      
2494                     } else {                                                                             
2495                         otherScreenItems.add(info);                                                      
2496                     }                                                                                    
2497                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2498                     currentScreenItems.add(info);                                                        
2499                     itemsOnScreen.add(info.id);                                                          
2500                 } else {                                                                                 
2501                     if (itemsOnScreen.contains(info.container)) {                                        
2502                         currentScreenItems.add(info);                                                    
2503                         itemsOnScreen.add(info.id);                                                      
2504                     } else {                                                                             
2505                         otherScreenItems.add(info);                                                      
2506                     }                                                                                    
2507                 }                                                                                        
2508             }                                                                                            
2509         }                                                                                                
2510                                                                                                          
2511         /** Filters the set of widgets which are on the specified screen. */                             
2512         private void filterCurrentAppWidgets(long currentScreenId,                                       
2513                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2514                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2515                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2516                                                                                                          
2517             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2518                 if (widget == null) continue;                                                            
2519                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2520                         widget.screenId == currentScreenId) {                                            
2521                     currentScreenWidgets.add(widget);                                                    
2522                 } else {                                                                                 
2523                     otherScreenWidgets.add(widget);                                                      
2524                 }                                                                                        
2525             }                                                                                            
2526         }                                                                                                
2527                                                                                                          
2528         /** Filters the set of folders which are on the specified screen. */                             
2529         private void filterCurrentFolders(long currentScreenId,                                          
2530                 HashMap<Long, ItemInfo> itemsIdMap,                                                      
2531                 HashMap<Long, FolderInfo> folders,                                                       
2532                 HashMap<Long, FolderInfo> currentScreenFolders,                                          
2533                 HashMap<Long, FolderInfo> otherScreenFolders) {                                          
2534                                                                                                          
2535             for (long id : folders.keySet()) {                                                           
2536                 ItemInfo info = itemsIdMap.get(id);                                                      
2537                 FolderInfo folder = folders.get(id);                                                     
2538                 if (info == null || folder == null) continue;                                            
2539                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2540                         info.screenId == currentScreenId) {                                              
2541                     currentScreenFolders.put(id, folder);                                                
2542                 } else {                                                                                 
2543                     otherScreenFolders.put(id, folder);                                                  
2544                 }                                                                                        
2545             }                                                                                            
2546         }                                                                                                
2547                                                                                                          
2548         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2549          * right) */                                                                                     
2550         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2551             final LauncherAppState app = LauncherAppState.getInstance();                                 
2552             final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                          
2553             // XXX: review this                                                                          
2554             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2555                 @Override                                                                                
2556                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2557                     int cellCountX = (int) grid.numColumns;                                              
2558                     int cellCountY = (int) grid.numRows;                                                 
2559                     int screenOffset = cellCountX * cellCountY;                                          
2560                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2561                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2562                             lhs.cellY * cellCountX + lhs.cellX);                                         
2563                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2564                             rhs.cellY * cellCountX + rhs.cellX);                                         
2565                     return (int) (lr - rr);                                                              
2566                 }                                                                                        
2567             });                                                                                          
2568         }                                                                                                
2569                                                                                                          
2570         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2571                 final ArrayList<Long> orderedScreens) {                                                  
2572             final Runnable r = new Runnable() {                                                          
2573                 @Override                                                                                
2574                 public void run() {                                                                      
2575                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2576                     if (callbacks != null) {                                                             
2577                         callbacks.bindScreens(orderedScreens);                                           
2578                     }                                                                                    
2579                 }                                                                                        
2580             };                                                                                           
2581             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2582         }                                                                                                
2583                                                                                                          
2584         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2585                 final ArrayList<ItemInfo> workspaceItems,                                                
2586                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2587                 final HashMap<Long, FolderInfo> folders,                                                 
2588                 ArrayList<Runnable> deferredBindRunnables) {                                             
2589                                                                                                          
2590             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2591                                                                                                          
2592             // Bind the workspace items                                                                  
2593             int N = workspaceItems.size();                                                               
2594             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2595                 final int start = i;                                                                     
2596                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2597                 final Runnable r = new Runnable() {                                                      
2598                     @Override                                                                            
2599                     public void run() {                                                                  
2600                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2601                         if (callbacks != null) {                                                         
2602                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2603                                     false);                                                              
2604                         }                                                                                
2605                     }                                                                                    
2606                 };                                                                                       
2607                 if (postOnMainThread) {                                                                  
2608                     deferredBindRunnables.add(r);                                                        
2609                 } else {                                                                                 
2610                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2611                 }                                                                                        
2612             }                                                                                            
2613                                                                                                          
2614             // Bind the folders                                                                          
2615             if (!folders.isEmpty()) {                                                                    
2616                 final Runnable r = new Runnable() {                                                      
2617                     public void run() {                                                                  
2618                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2619                         if (callbacks != null) {                                                         
2620                             callbacks.bindFolders(folders);                                              
2621                         }                                                                                
2622                     }                                                                                    
2623                 };                                                                                       
2624                 if (postOnMainThread) {                                                                  
2625                     deferredBindRunnables.add(r);                                                        
2626                 } else {                                                                                 
2627                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2628                 }                                                                                        
2629             }                                                                                            
2630                                                                                                          
2631             // Bind the widgets, one at a time                                                           
2632             N = appWidgets.size();                                                                       
2633             for (int i = 0; i < N; i++) {                                                                
2634                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2635                 final Runnable r = new Runnable() {                                                      
2636                     public void run() {                                                                  
2637                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2638                         if (callbacks != null) {                                                         
2639                             callbacks.bindAppWidget(widget);                                             
2640                         }                                                                                
2641                     }                                                                                    
2642                 };                                                                                       
2643                 if (postOnMainThread) {                                                                  
2644                     deferredBindRunnables.add(r);                                                        
2645                 } else {                                                                                 
2646                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2647                 }                                                                                        
2648             }                                                                                            
2649         }                                                                                                
2650                                                                                                          
2651         /**                                                                                              
2652          * Binds all loaded data to actual views on the main thread.                                     
2653          */                                                                                              
2654         private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {               
2655             final long t = SystemClock.uptimeMillis();                                                   
2656             Runnable r;                                                                                  
2657                                                                                                          
2658             // Don't use these two variables in any of the callback runnables.                           
2659             // Otherwise we hold a reference to them.                                                    
2660             final Callbacks oldCallbacks = mCallbacks.get();                                             
2661             if (oldCallbacks == null) {                                                                  
2662                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2663                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2664                 return;                                                                                  
2665             }                                                                                            
2666                                                                                                          
2667             // Save a copy of all the bg-thread collections                                              
2668             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2669             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2670                     new ArrayList<LauncherAppWidgetInfo>();                                              
2671             HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                         
2672             HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                          
2673             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2674             synchronized (sBgLock) {                                                                     
2675                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2676                 appWidgets.addAll(sBgAppWidgets);                                                        
2677                 folders.putAll(sBgFolders);                                                              
2678                 itemsIdMap.putAll(sBgItemsIdMap);                                                        
2679                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2680             }                                                                                            
2681                                                                                                          
2682             final boolean isLoadingSynchronously =                                                       
2683                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2684             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2685                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2686             if (currScreen >= orderedScreenIds.size()) {                                                 
2687                 // There may be no workspace screens (just hotseat items and an empty page).             
2688                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2689             }                                                                                            
2690             final int currentScreen = currScreen;                                                        
2691             final long currentScreenId = currentScreen < 0                                               
2692                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2693                                                                                                          
2694             // Load all the items that are on the current page first (and in the process, unbind         
2695             // all the existing workspace items before we call startBinding() below.                     
2696             unbindWorkspaceItemsOnMainThread();                                                          
2697                                                                                                          
2698             // Separate the items that are on the current screen, and all the other remaining items      
2699             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2700             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2701             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2702                     new ArrayList<LauncherAppWidgetInfo>();                                              
2703             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2704                     new ArrayList<LauncherAppWidgetInfo>();                                              
2705             HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                  
2706             HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                    
2707                                                                                                          
2708             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2709                     otherWorkspaceItems);                                                                
2710             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2711                     otherAppWidgets);                                                                    
2712             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2713                     otherFolders);                                                                       
2714             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2715             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2716                                                                                                          
2717             // Tell the workspace that we're about to start binding items                                
2718             r = new Runnable() {                                                                         
2719                 public void run() {                                                                      
2720                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2721                     if (callbacks != null) {                                                             
2722                         callbacks.startBinding();                                                        
2723                     }                                                                                    
2724                 }                                                                                        
2725             };                                                                                           
2726             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2727                                                                                                          
2728             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2729                                                                                                          
2730             // Load items on the current page                                                            
2731             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2732                     currentFolders, null);                                                               
2733             if (isLoadingSynchronously) {                                                                
2734                 r = new Runnable() {                                                                     
2735                     public void run() {                                                                  
2736                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2737                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2738                             callbacks.onPageBoundSynchronously(currentScreen);                           
2739                         }                                                                                
2740                     }                                                                                    
2741                 };                                                                                       
2742                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2743             }                                                                                            
2744                                                                                                          
2745             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2746             // work until after the first render)                                                        
2747             mDeferredBindRunnables.clear();                                                              
2748             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2749                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2750                                                                                                          
2751             // Tell the workspace that we're done binding items                                          
2752             r = new Runnable() {                                                                         
2753                 public void run() {                                                                      
2754                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2755                     if (callbacks != null) {                                                             
2756                         callbacks.finishBindingItems(isUpgradePath);                                     
2757                     }                                                                                    
2758                                                                                                          
2759                     // If we're profiling, ensure this is the last thing in the queue.                   
2760                     if (DEBUG_LOADERS) {                                                                 
2761                         Log.d(TAG, "bound workspace in "                                                 
2762                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2763                     }                                                                                    
2764                                                                                                          
2765                     mIsLoadingAndBindingWorkspace = false;                                               
2766                 }                                                                                        
2767             };                                                                                           
2768             if (isLoadingSynchronously) {                                                                
2769                 mDeferredBindRunnables.add(r);                                                           
2770             } else {                                                                                     
2771                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2772             }                                                                                            
2773         }                                                                                                
2774                                                                                                          
2775         private void loadAndBindAllApps() {                                                              
2776             if (DEBUG_LOADERS) {                                                                         
2777                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2778             }                                                                                            
2779             if (!mAllAppsLoaded) {                                                                       
2780                 loadAllApps();                                                                           
2781                 synchronized (LoaderTask.this) {                                                         
2782                     if (mStopped) {                                                                      
2783                         return;                                                                          
2784                     }                                                                                    
2785                     mAllAppsLoaded = true;                                                               
2786                 }                                                                                        
2787             } else {                                                                                     
2788                 onlyBindAllApps();                                                                       
2789             }                                                                                            
2790         }                                                                                                
2791                                                                                                          
2792         private void onlyBindAllApps() {                                                                 
2793             final Callbacks oldCallbacks = mCallbacks.get();                                             
2794             if (oldCallbacks == null) {                                                                  
2795                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2796                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2797                 return;                                                                                  
2798             }                                                                                            
2799                                                                                                          
2800             // shallow copy                                                                              
2801             @SuppressWarnings("unchecked")                                                               
2802             final ArrayList<AppInfo> list                                                                
2803                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2804             Runnable r = new Runnable() {                                                                
2805                 public void run() {                                                                      
2806                     final long t = SystemClock.uptimeMillis();                                           
2807                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2808                     if (callbacks != null) {                                                             
2809                         callbacks.bindAllApplications(list);                                             
2810                     }                                                                                    
2811                     if (DEBUG_LOADERS) {                                                                 
2812                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2813                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2814                     }                                                                                    
2815                 }                                                                                        
2816             };                                                                                           
2817             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2818             if (isRunningOnMainThread) {                                                                 
2819                 r.run();                                                                                 
2820             } else {                                                                                     
2821                 mHandler.post(r);                                                                        
2822             }                                                                                            
2823         }                                                                                                
2824                                                                                                          
2825         private void loadAllApps() {                                                                     
2826             final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2827                                                                                                          
2828             final Callbacks oldCallbacks = mCallbacks.get();                                             
2829             if (oldCallbacks == null) {                                                                  
2830                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2831                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2832                 return;                                                                                  
2833             }                                                                                            
2834                                                                                                          
2835             final PackageManager packageManager = mContext.getPackageManager();                          
2836             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                              
2837             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                            
2838                                                                                                          
2839             // Clear the list of apps                                                                    
2840             mBgAllAppsList.clear();                                                                      
2841                                                                                                          
2842             // Query for the set of apps                                                                 
2843             final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                         
2844             List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);                
2845             if (DEBUG_LOADERS) {                                                                         
2846                 Log.d(TAG, "queryIntentActivities took "                                                 
2847                         + (SystemClock.uptimeMillis()-qiaTime) + "ms");                                  
2848                 Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");                        
2849             }                                                                                            
2850             // Fail if we don't have any apps                                                            
2851             if (apps == null || apps.isEmpty()) {                                                        
2852                 return;                                                                                  
2853             }                                                                                            
2854             // Sort the applications by name                                                             
2855             final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2856             Collections.sort(apps,                                                                       
2857                     new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));              
2858             if (DEBUG_LOADERS) {                                                                         
2859                 Log.d(TAG, "sort took "                                                                  
2860                         + (SystemClock.uptimeMillis()-sortTime) + "ms");                                 
2861             }                                                                                            
2862                                                                                                          
2863             // Create the ApplicationInfos                                                               
2864             for (int i = 0; i < apps.size(); i++) {                                                      
2865                 ResolveInfo app = apps.get(i);                                                           
2866                 // This builds the icon bitmaps.                                                         
2867                 mBgAllAppsList.add(new AppInfo(packageManager, app,                                      
2868                         mIconCache, mLabelCache));                                                       
2869             }                                                                                            
2870                                                                                                          
2871             // Huh? Shouldn't this be inside the Runnable below?                                         
2872             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2873             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2874                                                                                                          
2875             // Post callback on main thread                                                              
2876             mHandler.post(new Runnable() {                                                               
2877                 public void run() {                                                                      
2878                     final long bindTime = SystemClock.uptimeMillis();                                    
2879                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2880                     if (callbacks != null) {                                                             
2881                         callbacks.bindAllApplications(added);                                            
2882                         if (DEBUG_LOADERS) {                                                             
2883                             Log.d(TAG, "bound " + added.size() + " apps in "                             
2884                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");                       
2885                         }                                                                                
2886                     } else {                                                                             
2887                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2888                     }                                                                                    
2889                 }                                                                                        
2890             });                                                                                          
2891                                                                                                          
2892             if (DEBUG_LOADERS) {                                                                         
2893                 Log.d(TAG, "Icons processed in "                                                         
2894                         + (SystemClock.uptimeMillis() - loadTime) + "ms");                               
2895             }                                                                                            
2896         }                                                                                                
2897                                                                                                          
2898         public void dumpState() {                                                                        
2899             synchronized (sBgLock) {                                                                     
2900                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2901                 Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                  
2902                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2903                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2904                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2905             }                                                                                            
2906         }                                                                                                
2907     }                                                                                                    
2908                                                                                                          
2909     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2910         sWorker.post(task);                                                                              
2911     }                                                                                                    
2912                                                                                                          
2913     private class PackageUpdatedTask implements Runnable {                                               
2914         int mOp;                                                                                         
2915         String[] mPackages;                                                                              
2916                                                                                                          
2917         public static final int OP_NONE = 0;                                                             
2918         public static final int OP_ADD = 1;                                                              
2919         public static final int OP_UPDATE = 2;                                                           
2920         public static final int OP_REMOVE = 3; // uninstlled                                             
2921         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2922                                                                                                          
2923                                                                                                          
2924         public PackageUpdatedTask(int op, String[] packages) {                                           
2925             mOp = op;                                                                                    
2926             mPackages = packages;                                                                        
2927         }                                                                                                
2928                                                                                                          
2929         public void run() {                                                                              
2930             final Context context = mApp.getContext();                                                   
2931                                                                                                          
2932             final String[] packages = mPackages;                                                         
2933             final int N = packages.length;                                                               
2934             switch (mOp) {                                                                               
2935                 case OP_ADD:                                                                             
2936                     for (int i=0; i<N; i++) {                                                            
2937                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);         
2938                         mBgAllAppsList.addPackage(context, packages[i]);                                 
2939                     }                                                                                    
2940                     break;                                                                               
2941                 case OP_UPDATE:                                                                          
2942                     for (int i=0; i<N; i++) {                                                            
2943                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);      
2944                         mBgAllAppsList.updatePackage(context, packages[i]);                              
2945                         WidgetPreviewLoader.removePackageFromDb(                                         
2946                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
2947                     }                                                                                    
2948                     break;                                                                               
2949                 case OP_REMOVE:                                                                          
2950                 case OP_UNAVAILABLE:                                                                     
2951                     for (int i=0; i<N; i++) {                                                            
2952                         if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);      
2953                         mBgAllAppsList.removePackage(packages[i]);                                       
2954                         WidgetPreviewLoader.removePackageFromDb(                                         
2955                                 mApp.getWidgetPreviewCacheDb(), packages[i]);                            
2956                     }                                                                                    
2957                     break;                                                                               
2958             }                                                                                            
2959                                                                                                          
2960             ArrayList<AppInfo> added = null;                                                             
2961             ArrayList<AppInfo> modified = null;                                                          
2962             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
2963                                                                                                          
2964             if (mBgAllAppsList.added.size() > 0) {                                                       
2965                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
2966                 mBgAllAppsList.added.clear();                                                            
2967             }                                                                                            
2968             if (mBgAllAppsList.modified.size() > 0) {                                                    
2969                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
2970                 mBgAllAppsList.modified.clear();                                                         
2971             }                                                                                            
2972             if (mBgAllAppsList.removed.size() > 0) {                                                     
2973                 removedApps.addAll(mBgAllAppsList.removed);                                              
2974                 mBgAllAppsList.removed.clear();                                                          
2975             }                                                                                            
2976                                                                                                          
2977             final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                    
2978             if (callbacks == null) {                                                                     
2979                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
2980                 return;                                                                                  
2981             }                                                                                            
2982                                                                                                          
2983             if (added != null) {                                                                         
2984                 // Ensure that we add all the workspace applications to the db                           
2985                 Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                             
2986                 if (!LauncherAppState.isDisableAllApps()) {                                              
2987                     addAndBindAddedApps(context, new ArrayList<ItemInfo>(), cb, added);                  
2988                 } else {                                                                                 
2989                     final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);               
2990                     addAndBindAddedApps(context, addedInfos, cb, added);                                 
2991                 }                                                                                        
2992             }                                                                                            
2993             if (modified != null) {                                                                      
2994                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
2995                                                                                                          
2996                 // Update the launcher db to reflect the changes                                         
2997                 for (AppInfo a : modifiedFinal) {                                                        
2998                     ArrayList<ItemInfo> infos =                                                          
2999                             getItemInfoForComponentName(a.componentName);                                
3000                     for (ItemInfo i : infos) {                                                           
3001                         if (isShortcutInfoUpdateable(i)) {                                               
3002                             ShortcutInfo info = (ShortcutInfo) i;                                        
3003                             info.title = a.title.toString();                                             
3004                             updateItemInDatabase(context, info);                                         
3005                         }                                                                                
3006                     }                                                                                    
3007                 }                                                                                        
3008                                                                                                          
3009                 mHandler.post(new Runnable() {                                                           
3010                     public void run() {                                                                  
3011                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
3012                         if (callbacks == cb && cb != null) {                                             
3013                             callbacks.bindAppsUpdated(modifiedFinal);                                    
3014                         }                                                                                
3015                     }                                                                                    
3016                 });                                                                                      
3017             }                                                                                            
3018                                                                                                          
3019             final ArrayList<String> removedPackageNames =                                                
3020                     new ArrayList<String>();                                                             
3021             if (mOp == OP_REMOVE) {                                                                      
3022                 // Mark all packages in the broadcast to be removed                                      
3023                 removedPackageNames.addAll(Arrays.asList(packages));                                     
3024             } else if (mOp == OP_UPDATE) {                                                               
3025                 // Mark disabled packages in the broadcast to be removed                                 
3026                 final PackageManager pm = context.getPackageManager();                                   
3027                 for (int i=0; i<N; i++) {                                                                
3028                     if (isPackageDisabled(pm, packages[i])) {                                            
3029                         removedPackageNames.add(packages[i]);                                            
3030                     }                                                                                    
3031                 }                                                                                        
3032             }                                                                                            
3033             // Remove all the components associated with this package                                    
3034             for (String pn : removedPackageNames) {                                                      
3035                 ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);                               
3036                 for (ItemInfo i : infos) {                                                               
3037                     deleteItemFromDatabase(context, i);                                                  
3038                 }                                                                                        
3039             }                                                                                            
3040             // Remove all the specific components                                                        
3041             for (AppInfo a : removedApps) {                                                              
3042                 ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);                
3043                 for (ItemInfo i : infos) {                                                               
3044                     deleteItemFromDatabase(context, i);                                                  
3045                 }                                                                                        
3046             }                                                                                            
3047             if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                              
3048                 // Remove any queued items from the install queue                                        
3049                 String spKey = LauncherAppState.getSharedPreferencesKey();                               
3050                 SharedPreferences sp =                                                                   
3051                         context.getSharedPreferences(spKey, Context.MODE_PRIVATE);                       
3052                 InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames);                 
3053                 // Call the components-removed callback                                                  
3054                 mHandler.post(new Runnable() {                                                           
3055                     public void run() {                                                                  
3056                         Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                     
3057                         if (callbacks == cb && cb != null) {                                             
3058                             callbacks.bindComponentsRemoved(removedPackageNames, removedApps);           
3059                         }                                                                                
3060                     }                                                                                    
3061                 });                                                                                      
3062             }                                                                                            
3063                                                                                                          
3064             final ArrayList<Object> widgetsAndShortcuts =                                                
3065                 getSortedWidgetsAndShortcuts(context);                                                   
3066             mHandler.post(new Runnable() {                                                               
3067                 @Override                                                                                
3068                 public void run() {                                                                      
3069                     Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                         
3070                     if (callbacks == cb && cb != null) {                                                 
3071                         callbacks.bindPackagesUpdated(widgetsAndShortcuts);                              
3072                     }                                                                                    
3073                 }                                                                                        
3074             });                                                                                          
3075                                                                                                          
3076             // Write all the logs to disk                                                                
3077             mHandler.post(new Runnable() {                                                               
3078                 public void run() {                                                                      
3079                     Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                         
3080                     if (callbacks == cb && cb != null) {                                                 
3081                         callbacks.dumpLogsToLocalData();                                                 
3082                     }                                                                                    
3083                 }                                                                                        
3084             });                                                                                          
3085         }                                                                                                
3086     }                                                                                                    
3087                                                                                                          
3088     // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                     
3089     public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                      
3090         PackageManager packageManager = context.getPackageManager();                                     
3091         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
3092         widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders());       
3093         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
3094         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
3095         Collections.sort(widgetsAndShortcuts,                                                            
3096             new LauncherModel.WidgetAndShortcutNameComparator(packageManager));                          
3097         return widgetsAndShortcuts;                                                                      
3098     }                                                                                                    
3099                                                                                                          
3100     private static boolean isPackageDisabled(PackageManager pm, String packageName) {                    
3101         try {                                                                                            
3102             PackageInfo pi = pm.getPackageInfo(packageName, 0);                                          
3103             return !pi.applicationInfo.enabled;                                                          
3104         } catch (NameNotFoundException e) {                                                              
3105             // Fall through                                                                              
3106         }                                                                                                
3107         return false;                                                                                    
3108     }                                                                                                    
3109                                                                                                          
3110     public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) {                 
3111         if (cn == null) {                                                                                
3112             return false;                                                                                
3113         }                                                                                                
3114         if (isPackageDisabled(pm, cn.getPackageName())) {                                                
3115             return false;                                                                                
3116         }                                                                                                
3117                                                                                                          
3118         try {                                                                                            
3119             // Check the activity                                                                        
3120             PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0);                                  
3121             return (pm.getActivityInfo(cn, 0) != null);                                                  
3122         } catch (NameNotFoundException e) {                                                              
3123             return false;                                                                                
3124         }                                                                                                
3125     }                                                                                                    
3126                                                                                                          
3127     /**                                                                                                  
3128      * Make an ShortcutInfo object for a restored application or shortcut item that points               
3129      * to a package that is not yet installed on the system.                                             
3130      */                                                                                                  
3131     public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) {              
3132         final ShortcutInfo info = new ShortcutInfo();                                                    
3133         info.usingFallbackIcon = true;                                                                   
3134         info.setIcon(getFallbackIcon());                                                                 
3135         if (cursor != null) {                                                                            
3136             info.title =  cursor.getString(titleIndex);                                                  
3137         } else {                                                                                         
3138             info.title = "";                                                                             
3139         }                                                                                                
3140         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3141         info.restoredIntent = intent;                                                                    
3142         return info;                                                                                     
3143     }                                                                                                    
3144                                                                                                          
3145     /**                                                                                                  
3146      * Make an Intent object for a restored application or shortcut item that points                     
3147      * to the market page for the item.                                                                  
3148      */                                                                                                  
3149     private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                     
3150         final boolean debug = false;                                                                     
3151         ComponentName componentName = intent.getComponent();                                             
3152         Intent marketIntent = new Intent(Intent.ACTION_VIEW);                                            
3153         Uri marketUri = new Uri.Builder()                                                                
3154                 .scheme("market")                                                                        
3155                 .authority("details")                                                                    
3156                 .appendQueryParameter("id", componentName.getPackageName())                              
3157                 .build();                                                                                
3158         if (debug) Log.d(TAG, "manufactured intent uri: " + marketUri.toString());                       
3159         marketIntent.setData(marketUri);                                                                 
3160         return marketIntent;                                                                             
3161     }                                                                                                    
3162                                                                                                          
3163     /**                                                                                                  
3164      * This is called from the code that adds shortcuts from the intent receiver.  This                  
3165      * doesn't have a Cursor, but                                                                        
3166      */                                                                                                  
3167     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {        
3168         return getShortcutInfo(manager, intent, context, null, -1, -1, null);                            
3169     }                                                                                                    
3170                                                                                                          
3171     /**                                                                                                  
3172      * Make an ShortcutInfo object for a shortcut that is an application.                                
3173      *                                                                                                   
3174      * If c is not null, then it will be used to fill in missing data like the title and icon.           
3175      */                                                                                                  
3176     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,          
3177             Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {         
3178         ComponentName componentName = intent.getComponent();                                             
3179         final ShortcutInfo info = new ShortcutInfo();                                                    
3180         if (componentName != null && !isValidPackageComponent(manager, componentName)) {                 
3181             Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName);                    
3182             return null;                                                                                 
3183         } else {                                                                                         
3184             try {                                                                                        
3185                 PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);              
3186                 info.initFlagsAndFirstInstallTime(pi);                                                   
3187             } catch (NameNotFoundException e) {                                                          
3188                 Log.d(TAG, "getPackInfo failed for package " +                                           
3189                         componentName.getPackageName());                                                 
3190             }                                                                                            
3191         }                                                                                                
3192                                                                                                          
3193         // TODO: See if the PackageManager knows about this case.  If it doesn't                         
3194         // then return null & delete this.                                                               
3195                                                                                                          
3196         // the resource -- This may implicitly give us back the fallback icon,                           
3197         // but don't worry about that.  All we're doing with usingFallbackIcon is                        
3198         // to avoid saving lots of copies of that in the database, and most apps                         
3199         // have icons anyway.                                                                            
3200                                                                                                          
3201         // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and      
3202         // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info     
3203         // via resolveActivity().                                                                        
3204         Bitmap icon = null;                                                                              
3205         ResolveInfo resolveInfo = null;                                                                  
3206         ComponentName oldComponent = intent.getComponent();                                              
3207         Intent newIntent = new Intent(intent.getAction(), null);                                         
3208         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
3209         newIntent.setPackage(oldComponent.getPackageName());                                             
3210         List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);                           
3211         for (ResolveInfo i : infos) {                                                                    
3212             ComponentName cn = new ComponentName(i.activityInfo.packageName,                             
3213                     i.activityInfo.name);                                                                
3214             if (cn.equals(oldComponent)) {                                                               
3215                 resolveInfo = i;                                                                         
3216             }                                                                                            
3217         }                                                                                                
3218         if (resolveInfo == null) {                                                                       
3219             resolveInfo = manager.resolveActivity(intent, 0);                                            
3220         }                                                                                                
3221         if (resolveInfo != null) {                                                                       
3222             icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);                           
3223         }                                                                                                
3224         // the db                                                                                        
3225         if (icon == null) {                                                                              
3226             if (c != null) {                                                                             
3227                 icon = getIconFromCursor(c, iconIndex, context);                                         
3228             }                                                                                            
3229         }                                                                                                
3230         // the fallback icon                                                                             
3231         if (icon == null) {                                                                              
3232             icon = getFallbackIcon();                                                                    
3233             info.usingFallbackIcon = true;                                                               
3234         }                                                                                                
3235         info.setIcon(icon);                                                                              
3236                                                                                                          
3237         // from the resource                                                                             
3238         if (resolveInfo != null) {                                                                       
3239             ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);              
3240             if (labelCache != null && labelCache.containsKey(key)) {                                     
3241                 info.title = labelCache.get(key);                                                        
3242             } else {                                                                                     
3243                 info.title = resolveInfo.activityInfo.loadLabel(manager);                                
3244                 if (labelCache != null) {                                                                
3245                     labelCache.put(key, info.title);                                                     
3246                 }                                                                                        
3247             }                                                                                            
3248         }                                                                                                
3249         // from the db                                                                                   
3250         if (info.title == null) {                                                                        
3251             if (c != null) {                                                                             
3252                 info.title =  c.getString(titleIndex);                                                   
3253             }                                                                                            
3254         }                                                                                                
3255         // fall back to the class name of the activity                                                   
3256         if (info.title == null) {                                                                        
3257             info.title = componentName.getClassName();                                                   
3258         }                                                                                                
3259         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
3260         return info;                                                                                     
3261     }                                                                                                    
3262                                                                                                          
3263     static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                               
3264             ItemInfoFilter f) {                                                                          
3265         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
3266         for (ItemInfo i : infos) {                                                                       
3267             if (i instanceof ShortcutInfo) {                                                             
3268                 ShortcutInfo info = (ShortcutInfo) i;                                                    
3269                 ComponentName cn = info.intent.getComponent();                                           
3270                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3271                     filtered.add(info);                                                                  
3272                 }                                                                                        
3273             } else if (i instanceof FolderInfo) {                                                        
3274                 FolderInfo info = (FolderInfo) i;                                                        
3275                 for (ShortcutInfo s : info.contents) {                                                   
3276                     ComponentName cn = s.intent.getComponent();                                          
3277                     if (cn != null && f.filterItem(info, s, cn)) {                                       
3278                         filtered.add(s);                                                                 
3279                     }                                                                                    
3280                 }                                                                                        
3281             } else if (i instanceof LauncherAppWidgetInfo) {                                             
3282                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
3283                 ComponentName cn = info.providerName;                                                    
3284                 if (cn != null && f.filterItem(null, info, cn)) {                                        
3285                     filtered.add(info);                                                                  
3286                 }                                                                                        
3287             }                                                                                            
3288         }                                                                                                
3289         return new ArrayList<ItemInfo>(filtered);                                                        
3290     }                                                                                                    
3291                                                                                                          
3292     private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {                             
3293         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3294             @Override                                                                                    
3295             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3296                 return cn.getPackageName().equals(pn);                                                   
3297             }                                                                                            
3298         };                                                                                               
3299         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
3300     }                                                                                                    
3301                                                                                                          
3302     private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {                 
3303         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
3304             @Override                                                                                    
3305             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
3306                 return cn.equals(cname);                                                                 
3307             }                                                                                            
3308         };                                                                                               
3309         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
3310     }                                                                                                    
3311                                                                                                          
3312     public static boolean isShortcutInfoUpdateable(ItemInfo i) {                                         
3313         if (i instanceof ShortcutInfo) {                                                                 
3314             ShortcutInfo info = (ShortcutInfo) i;                                                        
3315             // We need to check for ACTION_MAIN otherwise getComponent() might                           
3316             // return null for some shortcuts (for instance, for shortcuts to                            
3317             // web pages.)                                                                               
3318             Intent intent = info.intent;                                                                 
3319             ComponentName name = intent.getComponent();                                                  
3320             if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&                     
3321                     Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {                     
3322                 return true;                                                                             
3323             }                                                                                            
3324             // placeholder shortcuts get special treatment, let them through too.                        
3325             if (info.getRestoredIntent() != null) {                                                      
3326                 return true;                                                                             
3327             }                                                                                            
3328         }                                                                                                
3329         return false;                                                                                    
3330     }                                                                                                    
3331                                                                                                          
3332     /**                                                                                                  
3333      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
3334      */                                                                                                  
3335     private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                      
3336             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,               
3337             int titleIndex) {                                                                            
3338                                                                                                          
3339         Bitmap icon = null;                                                                              
3340         final ShortcutInfo info = new ShortcutInfo();                                                    
3341         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
3342                                                                                                          
3343         // TODO: If there's an explicit component and we can't install that, delete it.                  
3344                                                                                                          
3345         info.title = c.getString(titleIndex);                                                            
3346                                                                                                          
3347         int iconType = c.getInt(iconTypeIndex);                                                          
3348         switch (iconType) {                                                                              
3349         case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                              
3350             String packageName = c.getString(iconPackageIndex);                                          
3351             String resourceName = c.getString(iconResourceIndex);                                        
3352             PackageManager packageManager = context.getPackageManager();                                 
3353             info.customIcon = false;                                                                     
3354             // the resource                                                                              
3355             try {                                                                                        
3356                 Resources resources = packageManager.getResourcesForApplication(packageName);            
3357                 if (resources != null) {                                                                 
3358                     final int id = resources.getIdentifier(resourceName, null, null);                    
3359                     icon = Utilities.createIconBitmap(                                                   
3360                             mIconCache.getFullResIcon(resources, id), context);                          
3361                 }                                                                                        
3362             } catch (Exception e) {                                                                      
3363                 // drop this.  we have other places to look for icons                                    
3364             }                                                                                            
3365             // the db                                                                                    
3366             if (icon == null) {                                                                          
3367                 icon = getIconFromCursor(c, iconIndex, context);                                         
3368             }                                                                                            
3369             // the fallback icon                                                                         
3370             if (icon == null) {                                                                          
3371                 icon = getFallbackIcon();                                                                
3372                 info.usingFallbackIcon = true;                                                           
3373             }                                                                                            
3374             break;                                                                                       
3375         case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                
3376             icon = getIconFromCursor(c, iconIndex, context);                                             
3377             if (icon == null) {                                                                          
3378                 icon = getFallbackIcon();                                                                
3379                 info.customIcon = false;                                                                 
3380                 info.usingFallbackIcon = true;                                                           
3381             } else {                                                                                     
3382                 info.customIcon = true;                                                                  
3383             }                                                                                            
3384             break;                                                                                       
3385         default:                                                                                         
3386             icon = getFallbackIcon();                                                                    
3387             info.usingFallbackIcon = true;                                                               
3388             info.customIcon = false;                                                                     
3389             break;                                                                                       
3390         }                                                                                                
3391         info.setIcon(icon);                                                                              
3392         return info;                                                                                     
3393     }                                                                                                    
3394                                                                                                          
3395     Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                 
3396         @SuppressWarnings("all") // suppress dead code warning                                           
3397         final boolean debug = false;                                                                     
3398         if (debug) {                                                                                     
3399             Log.d(TAG, "getIconFromCursor app="                                                          
3400                     + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));           
3401         }                                                                                                
3402         byte[] data = c.getBlob(iconIndex);                                                              
3403         try {                                                                                            
3404             return Utilities.createIconBitmap(                                                           
3405                     BitmapFactory.decodeByteArray(data, 0, data.length), context);                       
3406         } catch (Exception e) {                                                                          
3407             return null;                                                                                 
3408         }                                                                                                
3409     }                                                                                                    
3410                                                                                                          
3411     ShortcutInfo addShortcut(Context context, Intent data, long container, int screen,                   
3412             int cellX, int cellY, boolean notify) {                                                      
3413         final ShortcutInfo info = infoFromShortcutIntent(context, data, null);                           
3414         if (info == null) {                                                                              
3415             return null;                                                                                 
3416         }                                                                                                
3417         addItemToDatabase(context, info, container, screen, cellX, cellY, notify);                       
3418                                                                                                          
3419         return info;                                                                                     
3420     }                                                                                                    
3421                                                                                                          
3422     /**                                                                                                  
3423      * Attempts to find an AppWidgetProviderInfo that matches the given component.                       
3424      */                                                                                                  
3425     AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,                        
3426             ComponentName component) {                                                                   
3427         List<AppWidgetProviderInfo> widgets =                                                            
3428             AppWidgetManager.getInstance(context).getInstalledProviders();                               
3429         for (AppWidgetProviderInfo info : widgets) {                                                     
3430             if (info.provider.equals(component)) {                                                       
3431                 return info;                                                                             
3432             }                                                                                            
3433         }                                                                                                
3434         return null;                                                                                     
3435     }                                                                                                    
3436                                                                                                          
3437     /**                                                                                                  
3438      * Returns a list of all the widgets that can handle configuration with a particular mimeType.       
3439      */                                                                                                  
3440     List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {        
3441         final PackageManager packageManager = context.getPackageManager();                               
3442         final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =                         
3443             new ArrayList<WidgetMimeTypeHandlerData>();                                                  
3444                                                                                                          
3445         final Intent supportsIntent =                                                                    
3446             new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);                         
3447         supportsIntent.setType(mimeType);                                                                
3448                                                                                                          
3449         // Create a set of widget configuration components that we can test against                      
3450         final List<AppWidgetProviderInfo> widgets =                                                      
3451             AppWidgetManager.getInstance(context).getInstalledProviders();                               
3452         final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =             
3453             new HashMap<ComponentName, AppWidgetProviderInfo>();                                         
3454         for (AppWidgetProviderInfo info : widgets) {                                                     
3455             configurationComponentToWidget.put(info.configure, info);                                    
3456         }                                                                                                
3457                                                                                                          
3458         // Run through each of the intents that can handle this type of clip data, and cross             
3459         // reference them with the components that are actual configuration components                   
3460         final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,        
3461                 PackageManager.MATCH_DEFAULT_ONLY);                                                      
3462         for (ResolveInfo info : activities) {                                                            
3463             final ActivityInfo activityInfo = info.activityInfo;                                         
3464             final ComponentName infoComponent = new ComponentName(activityInfo.packageName,              
3465                     activityInfo.name);                                                                  
3466             if (configurationComponentToWidget.containsKey(infoComponent)) {                             
3467                 supportedConfigurationActivities.add(                                                    
3468                         new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,                        
3469                                 configurationComponentToWidget.get(infoComponent)));                     
3470             }                                                                                            
3471         }                                                                                                
3472         return supportedConfigurationActivities;                                                         
3473     }                                                                                                    
3474                                                                                                          
3475     ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {             
3476         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3477         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3478         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3479                                                                                                          
3480         if (intent == null) {                                                                            
3481             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3482             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3483             return null;                                                                                 
3484         }                                                                                                
3485                                                                                                          
3486         Bitmap icon = null;                                                                              
3487         boolean customIcon = false;                                                                      
3488         ShortcutIconResource iconResource = null;                                                        
3489                                                                                                          
3490         if (bitmap != null && bitmap instanceof Bitmap) {                                                
3491             icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);          
3492             customIcon = true;                                                                           
3493         } else {                                                                                         
3494             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3495             if (extra != null && extra instanceof ShortcutIconResource) {                                
3496                 try {                                                                                    
3497                     iconResource = (ShortcutIconResource) extra;                                         
3498                     final PackageManager packageManager = context.getPackageManager();                   
3499                     Resources resources = packageManager.getResourcesForApplication(                     
3500                             iconResource.packageName);                                                   
3501                     final int id = resources.getIdentifier(iconResource.resourceName, null, null);       
3502                     icon = Utilities.createIconBitmap(                                                   
3503                             mIconCache.getFullResIcon(resources, id), context);                          
3504                 } catch (Exception e) {                                                                  
3505                     Log.w(TAG, "Could not load shortcut icon: " + extra);                                
3506                 }                                                                                        
3507             }                                                                                            
3508         }                                                                                                
3509                                                                                                          
3510         final ShortcutInfo info = new ShortcutInfo();                                                    
3511                                                                                                          
3512         if (icon == null) {                                                                              
3513             if (fallbackIcon != null) {                                                                  
3514                 icon = fallbackIcon;                                                                     
3515             } else {                                                                                     
3516                 icon = getFallbackIcon();                                                                
3517                 info.usingFallbackIcon = true;                                                           
3518             }                                                                                            
3519         }                                                                                                
3520         info.setIcon(icon);                                                                              
3521                                                                                                          
3522         info.title = name;                                                                               
3523         info.intent = intent;                                                                            
3524         info.customIcon = customIcon;                                                                    
3525         info.iconResource = iconResource;                                                                
3526                                                                                                          
3527         return info;                                                                                     
3528     }                                                                                                    
3529                                                                                                          
3530     boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,             
3531             int iconIndex) {                                                                             
3532         // If apps can't be on SD, don't even bother.                                                    
3533         if (!mAppsCanBeOnRemoveableStorage) {                                                            
3534             return false;                                                                                
3535         }                                                                                                
3536         // If this icon doesn't have a custom icon, check to see                                         
3537         // what's stored in the DB, and if it doesn't match what                                         
3538         // we're going to show, store what we are going to show back                                     
3539         // into the DB.  We do this so when we're loading, if the                                        
3540         // package manager can't find an icon (for example because                                       
3541         // the app is on SD) then we can use that instead.                                               
3542         if (!info.customIcon && !info.usingFallbackIcon) {                                               
3543             cache.put(info, c.getBlob(iconIndex));                                                       
3544             return true;                                                                                 
3545         }                                                                                                
3546         return false;                                                                                    
3547     }                                                                                                    
3548     void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                              
3549         boolean needSave = false;                                                                        
3550         try {                                                                                            
3551             if (data != null) {                                                                          
3552                 Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                      
3553                 Bitmap loaded = info.getIcon(mIconCache);                                                
3554                 needSave = !saved.sameAs(loaded);                                                        
3555             } else {                                                                                     
3556                 needSave = true;                                                                         
3557             }                                                                                            
3558         } catch (Exception e) {                                                                          
3559             needSave = true;                                                                             
3560         }                                                                                                
3561         if (needSave) {                                                                                  
3562             Log.d(TAG, "going to save icon bitmap for info=" + info);                                    
3563             // This is slower than is ideal, but this only happens once                                  
3564             // or when the app is updated with a new icon.                                               
3565             updateItemInDatabase(context, info);                                                         
3566         }                                                                                                
3567     }                                                                                                    
3568                                                                                                          
3569     /**                                                                                                  
3570      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3571      * or make a new one.                                                                                
3572      */                                                                                                  
3573     private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {             
3574         // See if a placeholder was created for us already                                               
3575         FolderInfo folderInfo = folders.get(id);                                                         
3576         if (folderInfo == null) {                                                                        
3577             // No placeholder -- create a new instance                                                   
3578             folderInfo = new FolderInfo();                                                               
3579             folders.put(id, folderInfo);                                                                 
3580         }                                                                                                
3581         return folderInfo;                                                                               
3582     }                                                                                                    
3583                                                                                                          
3584     public static final Comparator<AppInfo> getAppNameComparator() {                                     
3585         final Collator collator = Collator.getInstance();                                                
3586         return new Comparator<AppInfo>() {                                                               
3587             public final int compare(AppInfo a, AppInfo b) {                                             
3588                 int result = collator.compare(a.title.toString().trim(),                                 
3589                         b.title.toString().trim());                                                      
3590                 if (result == 0) {                                                                       
3591                     result = a.componentName.compareTo(b.componentName);                                 
3592                 }                                                                                        
3593                 return result;                                                                           
3594             }                                                                                            
3595         };                                                                                               
3596     }                                                                                                    
3597     public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                  
3598             = new Comparator<AppInfo>() {                                                                
3599         public final int compare(AppInfo a, AppInfo b) {                                                 
3600             if (a.firstInstallTime < b.firstInstallTime) return 1;                                       
3601             if (a.firstInstallTime > b.firstInstallTime) return -1;                                      
3602             return 0;                                                                                    
3603         }                                                                                                
3604     };                                                                                                   
3605     public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() {                    
3606         final Collator collator = Collator.getInstance();                                                
3607         return new Comparator<AppWidgetProviderInfo>() {                                                 
3608             public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {                 
3609                 return collator.compare(a.label.toString().trim(), b.label.toString().trim());           
3610             }                                                                                            
3611         };                                                                                               
3612     }                                                                                                    
3613     static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                             
3614         if (info.activityInfo != null) {                                                                 
3615             return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);             
3616         } else {                                                                                         
3617             return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);               
3618         }                                                                                                
3619     }                                                                                                    
3620     public static class ShortcutNameComparator implements Comparator<ResolveInfo> {                      
3621         private Collator mCollator;                                                                      
3622         private PackageManager mPackageManager;                                                          
3623         private HashMap<Object, CharSequence> mLabelCache;                                               
3624         ShortcutNameComparator(PackageManager pm) {                                                      
3625             mPackageManager = pm;                                                                        
3626             mLabelCache = new HashMap<Object, CharSequence>();                                           
3627             mCollator = Collator.getInstance();                                                          
3628         }                                                                                                
3629         ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {            
3630             mPackageManager = pm;                                                                        
3631             mLabelCache = labelCache;                                                                    
3632             mCollator = Collator.getInstance();                                                          
3633         }                                                                                                
3634         public final int compare(ResolveInfo a, ResolveInfo b) {                                         
3635             CharSequence labelA, labelB;                                                                 
3636             ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);                       
3637             ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);                       
3638             if (mLabelCache.containsKey(keyA)) {                                                         
3639                 labelA = mLabelCache.get(keyA);                                                          
3640             } else {                                                                                     
3641                 labelA = a.loadLabel(mPackageManager).toString().trim();                                 
3642                                                                                                          
3643                 mLabelCache.put(keyA, labelA);                                                           
3644             }                                                                                            
3645             if (mLabelCache.containsKey(keyB)) {                                                         
3646                 labelB = mLabelCache.get(keyB);                                                          
3647             } else {                                                                                     
3648                 labelB = b.loadLabel(mPackageManager).toString().trim();                                 
3649                                                                                                          
3650                 mLabelCache.put(keyB, labelB);                                                           
3651             }                                                                                            
3652             return mCollator.compare(labelA, labelB);                                                    
3653         }                                                                                                
3654     }                                                                                                    
3655     public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                  
3656         private Collator mCollator;                                                                      
3657         private PackageManager mPackageManager;                                                          
3658         private HashMap<Object, String> mLabelCache;                                                     
3659         WidgetAndShortcutNameComparator(PackageManager pm) {                                             
3660             mPackageManager = pm;                                                                        
3661             mLabelCache = new HashMap<Object, String>();                                                 
3662             mCollator = Collator.getInstance();                                                          
3663         }                                                                                                
3664         public final int compare(Object a, Object b) {                                                   
3665             String labelA, labelB;                                                                       
3666             if (mLabelCache.containsKey(a)) {                                                            
3667                 labelA = mLabelCache.get(a);                                                             
3668             } else {                                                                                     
3669                 labelA = (a instanceof AppWidgetProviderInfo) ?                                          
3670                     ((AppWidgetProviderInfo) a).label :                                                  
3671                     ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                      
3672                 mLabelCache.put(a, labelA);                                                              
3673             }                                                                                            
3674             if (mLabelCache.containsKey(b)) {                                                            
3675                 labelB = mLabelCache.get(b);                                                             
3676             } else {                                                                                     
3677                 labelB = (b instanceof AppWidgetProviderInfo) ?                                          
3678                     ((AppWidgetProviderInfo) b).label :                                                  
3679                     ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                      
3680                 mLabelCache.put(b, labelB);                                                              
3681             }                                                                                            
3682             return mCollator.compare(labelA, labelB);                                                    
3683         }                                                                                                
3684     }                                                                                                    
3685                                                                                                          
3686     public void dumpState() {                                                                            
3687         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3688         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3689         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3690         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3691         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3692         if (mLoaderTask != null) {                                                                       
3693             mLoaderTask.dumpState();                                                                     
3694         } else {                                                                                         
3695             Log.d(TAG, "mLoaderTask=null");                                                              
3696         }                                                                                                
3697     }                                                                                                    
3698 }                                                                                                        
   1 /*                                                                                                       
   2  * Copyright (C) 2008 The Android Open Source Project                                                    
   3  *                                                                                                       
   4  * Licensed under the Apache License, Version 2.0 (the "License");                                       
   5  * you may not use this file except in compliance with the License.                                      
   6  * You may obtain a copy of the License at                                                               
   7  *                                                                                                       
   8  *      http://www.apache.org/licenses/LICENSE-2.0                                                       
   9  *                                                                                                       
  10  * Unless required by applicable law or agreed to in writing, software                                   
  11  * distributed under the License is distributed on an "AS IS" BASIS,                                     
  12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                              
  13  * See the License for the specific language governing permissions and                                   
  14  * limitations under the License.                                                                        
  15  */                                                                                                      
  16 package com.android.launcher3;                                                                           
  17                                                                                                          
  18 import android.app.SearchManager;                                                                        
  19 import android.appwidget.AppWidgetManager;                                                               
  20 import android.appwidget.AppWidgetProviderInfo;                                                          
  21 import android.content.*;                                                                                
  22 import android.content.Intent.ShortcutIconResource;                                                      
  23 import android.content.pm.ActivityInfo;                                                                  
  24 import android.content.pm.PackageInfo;                                                                   
  25 import android.content.pm.PackageManager.NameNotFoundException;                                          
  26 import android.content.pm.PackageManager;                                                                
  27 import android.content.pm.ResolveInfo;                                                                   
  28 import android.content.res.Configuration;                                                                
  29 import android.content.res.Resources;                                                                    
  30 import android.database.Cursor;                                                                          
  31 import android.graphics.Bitmap;                                                                          
  32 import android.graphics.BitmapFactory;                                                                   
  33 import android.net.Uri;                                                                                  
  34 import android.os.Environment;                                                                           
  35 import android.os.Handler;                                                                               
  36 import android.os.HandlerThread;                                                                         
  37 import android.os.Parcelable;                                                                            
  38 import android.os.Process;                                                                               
  39 import android.os.RemoteException;                                                                       
  40 import android.os.SystemClock;                                                                           
  41 import android.provider.BaseColumns;                                                                     
  42 import android.text.TextUtils;                                                                           
  43 import android.util.Log;                                                                                 
  44 import android.util.Pair;                                                                                
  45 import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;                            
  46 import java.lang.ref.WeakReference;                                                                      
  47 import java.net.URISyntaxException;                                                                      
  48 import java.text.Collator;                                                                               
  49 import java.util.ArrayList;                                                                              
  50 import java.util.Arrays;                                                                                 
  51 import java.util.Collection;                                                                             
  52 import java.util.Collections;                                                                            
  53 import java.util.Comparator;                                                                             
  54 import java.util.HashMap;                                                                                
  55 import java.util.HashSet;                                                                                
  56 import java.util.Iterator;                                                                               
  57 import java.util.List;                                                                                   
  58 import java.util.Set;                                                                                    
  59 import java.util.TreeMap;                                                                                
  60 import java.util.concurrent.atomic.AtomicBoolean;                                                        
  61                                                                                                          
  62                                                                                                          
  63 /**                                                                                                      
  64  * Maintains in-memory state of the Launcher. It is expected that there should be only one               
  65  * LauncherModel object held in a static. Also provide APIs for updating the database state              
  66  * for the Launcher.                                                                                     
  67  */                                                                                                      
  68 public class LauncherModel extends BroadcastReceiver {                                                   
  69     static final boolean DEBUG_LOADERS = false;                                                          
  70                                                                                                          
  71     static final String TAG = "Launcher.Model";                                                          
  72                                                                                                          
  73     // true = use a "More Apps" folder for non-workspace apps on upgrade                                 
  74     // false = strew non-workspace apps across the workspace on upgrade                                  
  75     // true = use a "More Apps" folder for non-workspace apps on upgrade                                 
  76     // false = strew non-workspace apps across the workspace on upgrade                                  
  77     public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;                                    
  78                                                                                                          
  79     public static final int LOADER_FLAG_NONE = 0;                                                        
  80                                                                                                          
  81     public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                        
  82                                                                                                          
  83     public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                      
  84                                                                                                          
  85     // batch size for the workspace icons                                                                
  86     private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                      
  87                                                                                                          
  88     private static final long INVALID_SCREEN_ID = -1L;                                                   
  89                                                                                                          
  90     private final boolean mAppsCanBeOnRemoveableStorage;                                                 
  91                                                                                                          
  92     private final boolean mOldContentProviderExists;                                                     
  93                                                                                                          
  94     private final LauncherAppState mApp;                                                                 
  95                                                                                                          
  96     private final Object mLock = new Object();                                                           
  97                                                                                                          
  98     private DeferredHandler mHandler = new DeferredHandler();                                            
  99                                                                                                          
 100     private LoaderTask mLoaderTask;                                                                      
 101                                                                                                          
 102     private boolean mIsLoaderTaskRunning;                                                                
 103                                                                                                          
 104     private volatile boolean mFlushingWorkerThread;                                                      
 105                                                                                                          
 106     // Specific runnable types that are run on the main thread deferred handler, this allows us to       
 107     // clear all queued binding runnables when the Launcher activity is destroyed.                       
 108     private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                            
 109                                                                                                          
 110     private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                           
 111                                                                                                          
 112     private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");             
 113                                                                                                          
 114     static {                                                                                             
 115         sWorkerThread.start();                                                                           
 116     }                                                                                                    
 117                                                                                                          
 118     private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                       
 119                                                                                                          
 120     // We start off with everything not loaded.  After that, we assume that                              
 121     // our monitoring of the package manager provides all updates and we never                           
 122     // need to do a requery.  These are only ever touched from the loader thread.                        
 123     private boolean mWorkspaceLoaded;                                                                    
 124                                                                                                          
 125     private boolean mAllAppsLoaded;                                                                      
 126                                                                                                          
 127     // When we are loading pages synchronously, we can't just post the binding of items on the side      
 128     // pages as this delays the rotation process.  Instead, we wait for a callback from the first        
 129     // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start       
 130     // a normal load, we also clear this set of Runnables.                                               
 131     static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                 
 132                                                                                                          
 133     private WeakReference<Callbacks> mCallbacks;                                                         
 134                                                                                                          
 135     // < only access in worker thread >                                                                  
 136     // < only access in worker thread >                                                                  
 137     AllAppsList mBgAllAppsList;                                                                          
 138                                                                                                          
 139     // The lock that must be acquired before referencing any static bg data structures.  Unlike          
 140     // other locks, this one can generally be held long-term because we never expect any of these        
 141     // static data structures to be referenced outside of the worker thread except on the first          
 142     // load after configuration change.                                                                  
 143     static final Object sBgLock = new Object();                                                          
 144                                                                                                          
 145     // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by               
 146     // LauncherModel to their ids                                                                        
 147     static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                  
 148                                                                                                          
 149     // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts       
 150     // created by LauncherModel that are directly on the home screen (however, no widgets or             
 151     // shortcuts within folders).                                                                        
 152     static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                      
 153                                                                                                          
 154     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 155     // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()    
 156     static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                        
 157         new ArrayList<LauncherAppWidgetInfo>();                                                          
 158                                                                                                          
 159     // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                   
 160     static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                 
 161                                                                                                          
 162     // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database      
 163     static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                 
 164                                                                                                          
 165     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 166     // sBgWorkspaceScreens is the ordered set of workspace screens.                                      
 167     static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                            
 168                                                                                                          
 169     // </ only access in worker thread >                                                                 
 170     // </ only access in worker thread >                                                                 
 171                                                                                                          
 172     private IconCache mIconCache;                                                                        
 173                                                                                                          
 174     private Bitmap mDefaultIcon;                                                                         
 175                                                                                                          
 176     protected int mPreviousConfigMcc;                                                                    
 177                                                                                                          
 178     public interface Callbacks {                                                                         
 179         public abstract boolean setLoadOnResume();                                                       
 180                                                                                                          
 181         public abstract int getCurrentWorkspaceScreen();                                                 
 182                                                                                                          
 183         public abstract void startBinding();                                                             
 184                                                                                                          
 185         public abstract void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end, boolean forceAn🔵
 186                                                                                                          
 187         public abstract void bindScreens(ArrayList<Long> orderedScreenIds);                              
 188                                                                                                          
 189         public abstract void bindAddScreens(ArrayList<Long> orderedScreenIds);                           
 190                                                                                                          
 191         public abstract void bindFolders(HashMap<Long, FolderInfo> folders);                             
 192                                                                                                          
 193         public abstract void finishBindingItems(boolean upgradePath);                                    
 194                                                                                                          
 195         public abstract void bindAppWidget(LauncherAppWidgetInfo info);                                  
 196                                                                                                          
 197         public abstract void bindAllApplications(ArrayList<AppInfo> apps);                               
 198                                                                                                          
 199         public abstract void bindAppsAdded(ArrayList<Long> newScreens, ArrayList<ItemInfo> addNotAnimated🔵
 200                                                                                                          
 201         public abstract void bindAppsUpdated(ArrayList<AppInfo> apps);                                   
 202                                                                                                          
 203         public abstract void bindComponentsRemoved(ArrayList<String> packageNames, ArrayList<AppInfo> app🔵
 204                                                                                                          
 205         public abstract void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                 
 206                                                                                                          
 207         public abstract void bindSearchablesChanged();                                                   
 208                                                                                                          
 209         public abstract boolean isAllAppsButtonRank(int rank);                                           
 210                                                                                                          
 211         public abstract void onPageBoundSynchronously(int page);                                         
 212                                                                                                          
 213         public abstract void dumpLogsToLocalData();                                                      
 214     }                                                                                                    
 215                                                                                                          
 216     public interface ItemInfoFilter {                                                                    
 217         public abstract boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);            
 218     }                                                                                                    
 219                                                                                                          
 220     LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                      
 221         Context context = app.getContext();                                                              
 222         ContentResolver contentResolver = context.getContentResolver();                                  
 223         mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                        
 224         mOldContentProviderExists = contentResolver.acquireContentProviderClient(LauncherSettings.Favorit🔵
 225         mApp = app;                                                                                      
 226         mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                          
 227         mIconCache = iconCache;                                                                          
 228         final Resources res = context.getResources();                                                    
 229         Configuration config = res.getConfiguration();                                                   
 230         mPreviousConfigMcc = config.mcc;                                                                 
 231     }                                                                                                    
 232                                                                                                          
 233     /** Runs the specified runnable immediately if called from the main thread, otherwise it is          
 234      * posted on the main thread handler. */                                                             
 235     private void runOnMainThread(Runnable r) {                                                           
 236         runOnMainThread(r, 0);                                                                           
 237     }                                                                                                    
 238                                                                                                          
 239     private void runOnMainThread(Runnable r, int type) {                                                 
 240         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 241             // If we are on the worker thread, post onto the main handler                                
 242             mHandler.post(r);                                                                            
 243         } else {                                                                                         
 244             r.run();                                                                                     
 245         }                                                                                                
 246     }                                                                                                    
 247                                                                                                          
 248     /** Runs the specified runnable immediately if called from the worker thread, otherwise it is        
 249      * posted on the worker thread handler. */                                                           
 250     private static void runOnWorkerThread(Runnable r) {                                                  
 251         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 252             r.run();                                                                                     
 253         } else {                                                                                         
 254             // If we are not on the worker thread, then post to the worker handler                       
 255             sWorker.post(r);                                                                             
 256         }                                                                                                
 257     }                                                                                                    
 258                                                                                                          
 259     boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                             
 260         return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                         
 261     }                                                                                                    
 262                                                                                                          
 263     static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy,               
 264                                  long screen) {                                                          
 265         LauncherAppState app = LauncherAppState.getInstance();                                           
 266         DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                    
 267         final int xCount = (int) grid.numColumns;                                                        
 268         final int yCount = (int) grid.numRows;                                                           
 269         boolean[][] occupied = new boolean[xCount][yCount];                                              
 270                                                                                                          
 271         int cellX, cellY, spanX, spanY;                                                                  
 272         for (int i = 0; i < items.size(); ++i) {                                                         
 273             final ItemInfo item = items.get(i);                                                          
 274             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                        
 275                 if (item.screenId == screen) {                                                           
 276                     cellX = item.cellX;                                                                  
 277                     cellY = item.cellY;                                                                  
 278                     spanX = item.spanX;                                                                  
 279                     spanY = item.spanY;                                                                  
 280                     for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {                
 281                         for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {            
 282                             occupied[x][y] = true;                                                       
 283                         }                                                                                
 284                     }                                                                                    
 285                 }                                                                                        
 286             }                                                                                            
 287         }                                                                                                
 288                                                                                                          
 289         return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);                            
 290     }                                                                                                    
 291                                                                                                          
 292     static Pair<Long, int[]> findNextAvailableIconSpace(Context context, String name,                    
 293                                                         Intent launchIntent,                             
 294                                                         int firstScreenIndex,                            
 295                                                         ArrayList<Long> workspaceScreens) {              
 296         // Lock on the app so that we don't try and get the items while apps are being added             
 297         LauncherAppState app = LauncherAppState.getInstance();                                           
 298         LauncherModel model = app.getModel();                                                            
 299         boolean found = false;                                                                           
 300         synchronized (app) {                                                                             
 301             if (sWorkerThread.getThreadId() != Process.myTid()) {                                        
 302                 // Flush the LauncherModel worker thread, so that if we just did another                 
 303                 // processInstallShortcut, we give it time for its shortcut to get added to the          
 304                 // database (getItemsInLocalCoordinates reads the database)                              
 305                 model.flushWorkerThread();                                                               
 306             }                                                                                            
 307             final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);         
 308                                                                                                          
 309             // Try adding to the workspace screens incrementally, starting at the default or center      
 310             // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))       
 311             firstScreenIndex = Math.min(firstScreenIndex, workspaceScreens.size());                      
 312             int count = workspaceScreens.size();                                                         
 313             for (int screen = firstScreenIndex; screen < count && !found; screen++) {                    
 314                 int[] tmpCoordinates = new int[2];                                                       
 315                 if (findNextAvailableIconSpaceInScreen(items, tmpCoordinates,                            
 316                         workspaceScreens.get(screen))) {                                                 
 317                     // Update the Launcher db                                                            
 318                     return new Pair<Long, int[]>(workspaceScreens.get(screen), tmpCoordinates);          
 319                 }                                                                                        
 320             }                                                                                            
 321         }                                                                                                
 322         return null;                                                                                     
 323     }                                                                                                    
 324                                                                                                          
 325     public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps, final🔵
 326         Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;                                   
 327         addAndBindAddedApps(context, workspaceApps, cb, allAppsApps);                                    
 328     }                                                                                                    
 329                                                                                                          
 330     public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps, final🔵
 331         if ((workspaceApps == null) || (allAppsApps == null)) {                                          
 332             throw new RuntimeException("workspaceApps and allAppsApps must not be null");                
 333         }                                                                                                
 334         if (workspaceApps.isEmpty() && allAppsApps.isEmpty()) {                                          
 335             return;                                                                                      
 336         }                                                                                                
 337         // Process the newly added applications and add them to the database first                       
 338         Runnable r = new Runnable() {                                                                    
 339             public void run() {                                                                          
 340                 final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();               
 341                 final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                
 342                 final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();                   
 343                 // Get the list of workspace screens.  We need to append to this list and                
 344                 // can not use sBgWorkspaceScreens because loadWorkspace() may not have been             
 345                 // called.                                                                               
 346                 ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                
 347                 TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                 
 348                 for (Integer i : orderedScreens.keySet()) {                                              
 349                     long screenId = orderedScreens.get(i);                                               
 350                     workspaceScreens.add(screenId);                                                      
 351                 }                                                                                        
 352                 synchronized(sBgLock) {                                                                  
 353                     Iterator<ItemInfo> iter = workspaceApps.iterator();                                  
 354                     while (iter.hasNext()) {                                                             
 355                         ItemInfo a = iter.next();                                                        
 356                         final String name = a.title.toString();                                          
 357                         final Intent launchIntent = a.getIntent();                                       
 358                         // Short-circuit this logic if the icon exists somewhere on the workspace        
 359                         if (LauncherModel.shortcutExists(context, name, launchIntent)) {                 
 360                             // Only InstallShortcutReceiver sends us shortcutInfos, ignore them          
 361                             if ((a instanceof AppInfo) && LauncherModel.appWasRestored(context, launchInt🔵
 362                                 restoredAppsFinal.add(((AppInfo) (a)));                                  
 363                             }                                                                            
 364                             continue;                                                                    
 365                         }                                                                                
 366                         // Add this icon to the db, creating a new page if necessary.  If there          
 367                         // is only the empty page then we just add items to the first page.              
 368                         // Otherwise, we add them to the next pages.                                     
 369                         int startSearchPageIndex = (workspaceScreens.isEmpty()) ? 0 : 1;                 
 370                         Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context, name🔵
 371                         if (coords == null) {                                                            
 372                             LauncherProvider lp = LauncherAppState.getLauncherProvider();                
 373                             // If we can't find a valid position, then just add a new screen.            
 374                             // This takes time so we need to re-queue the add until the new              
 375                             // page is added.  Create as many screens as necessary to satisfy            
 376                             // the startSearchPageIndex.                                                 
 377                             int numPagesToAdd = Math.max(1, (startSearchPageIndex + 1) - workspaceScreens🔵
 378                             while (numPagesToAdd > 0) {                                                  
 379                                 long screenId = lp.generateNewScreenId();                                
 380                                 // Save the screen id for binding in the workspace                       
 381                                 workspaceScreens.add(screenId);                                          
 382                                 addedWorkspaceScreensFinal.add(screenId);                                
 383                                 numPagesToAdd--;                                                         
 384                             }                                                                            
 385                             // Find the coordinate again                                                 
 386                             coords = LauncherModel.findNextAvailableIconSpace(context, name, launchIntent🔵
 387                         }                                                                                
 388                         if (coords == null) {                                                            
 389                             throw new RuntimeException("Coordinates should not be null");                
 390                         }                                                                                
 391                         ShortcutInfo shortcutInfo;                                                       
 392                         if (a instanceof ShortcutInfo) {                                                 
 393                             shortcutInfo = ((ShortcutInfo) (a));                                         
 394                         } else if (a instanceof AppInfo) {                                               
 395                             shortcutInfo = ((AppInfo) (a)).makeShortcut();                               
 396                         } else {                                                                         
 397                             throw new RuntimeException("Unexpected info type");                          
 398                         }                                                                                
 399                         // Add the shortcut to the db                                                    
 400                         addItemToDatabase(context, shortcutInfo, LauncherSettings.Favorites.CONTAINER_DES🔵
 401                         // Save the ShortcutInfo for binding in the workspace                            
 402                         addedShortcutsFinal.add(shortcutInfo);                                           
 403                     }                                                                                    
 404                 }                                                                                        
 405                 // Update the workspace screens                                                          
 406                 updateWorkspaceScreenOrder(context, workspaceScreens);                                   
 407                 if ((!addedShortcutsFinal.isEmpty()) || (!allAppsApps.isEmpty())) {                      
 408                     runOnMainThread(new Runnable() {                                                     
 409                         public void run() {                                                              
 410                             Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;               
 411                             if ((callbacks == cb) && (cb != null)) {                                     
 412                                 final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();       
 413                                 final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();    
 414                                 if (!addedShortcutsFinal.isEmpty()) {                                    
 415                                     ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 🔵
 416                                     long lastScreenId = info.screenId;                                   
 417                                     for (ItemInfo i : addedShortcutsFinal) {                             
 418                                         if (i.screenId == lastScreenId) {                                
 419                                             addAnimated.add(i);                                          
 420                                         } else {                                                         
 421                                             addNotAnimated.add(i);                                       
 422                                         }                                                                
 423                                     }                                                                    
 424                                 }                                                                        
 425                                 callbacks.bindAppsAdded(addedWorkspaceScreensFinal, addNotAnimated, addAn🔵
 426                                 if (!restoredAppsFinal.isEmpty()) {                                      
 427                                     callbacks.bindAppsUpdated(restoredAppsFinal);                        
 428                                 }                                                                        
 429                             }                                                                            
 430                         }                                                                                
 431                     });                                                                                  
 432                 }                                                                                        
 433             }                                                                                            
 434         };                                                                                               
 435         runOnWorkerThread(r);                                                                            
 436     }                                                                                                    
 437                                                                                                          
 438     public Bitmap getFallbackIcon() {                                                                    
 439         if (mDefaultIcon == null) {                                                                      
 440             final Context context = LauncherAppState.getInstance().getContext();                         
 441             mDefaultIcon = Utilities.createIconBitmap(                                                   
 442                     mIconCache.getFullResDefaultActivityIcon(), context);                                
 443         }                                                                                                
 444         return Bitmap.createBitmap(mDefaultIcon);                                                        
 445     }                                                                                                    
 446                                                                                                          
 447     public void unbindItemInfosAndClearQueuedBindRunnables() {                                           
 448         if (sWorkerThread.getThreadId() == Process.myTid()) {                                            
 449             throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +     
 450                     "main thread");                                                                      
 451         }                                                                                                
 452                                                                                                          
 453         // Clear any deferred bind runnables                                                             
 454         mDeferredBindRunnables.clear();                                                                  
 455         // Remove any queued bind runnables                                                              
 456         mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                 
 457         // Unbind all the workspace items                                                                
 458         unbindWorkspaceItemsOnMainThread();                                                              
 459     }                                                                                                    
 460                                                                                                          
 461     /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                        
 462     void unbindWorkspaceItemsOnMainThread() {                                                            
 463         // Ensure that we don't use the same workspace items data structure on the main thread           
 464         // by making a copy of workspace items first.                                                    
 465         final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                         
 466         final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                             
 467         synchronized (sBgLock) {                                                                         
 468             tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                 
 469             tmpAppWidgets.addAll(sBgAppWidgets);                                                         
 470         }                                                                                                
 471         Runnable r = new Runnable() {                                                                    
 472                 @Override                                                                                
 473                 public void run() {                                                                      
 474                    for (ItemInfo item : tmpWorkspaceItems) {                                             
 475                        item.unbind();                                                                    
 476                    }                                                                                     
 477                    for (ItemInfo item : tmpAppWidgets) {                                                 
 478                        item.unbind();                                                                    
 479                    }                                                                                     
 480                 }                                                                                        
 481             };                                                                                           
 482         runOnMainThread(r);                                                                              
 483     }                                                                                                    
 484                                                                                                          
 485     /**                                                                                                  
 486      * Adds an item to the DB if it was not created previously, or move it to a new                      
 487      * <container, screen, cellX, cellY>                                                                 
 488      */                                                                                                  
 489     static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                  
 490             long screenId, int cellX, int cellY) {                                                       
 491         if (item.container == ItemInfo.NO_ID) {                                                          
 492             // From all apps                                                                             
 493             addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                  
 494         } else {                                                                                         
 495             // From somewhere else                                                                       
 496             moveItemInDatabase(context, item, container, screenId, cellX, cellY);                        
 497         }                                                                                                
 498     }                                                                                                    
 499                                                                                                          
 500     static void checkItemInfoLocked(                                                                     
 501             final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                    
 502         ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                  
 503         if (modelItem != null && item != modelItem) {                                                    
 504             // check all the data is consistent                                                          
 505             if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                     
 506                 ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                   
 507                 ShortcutInfo shortcut = (ShortcutInfo) item;                                             
 508                 if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                  
 509                         modelShortcut.intent.filterEquals(shortcut.intent) &&                            
 510                         modelShortcut.id == shortcut.id &&                                               
 511                         modelShortcut.itemType == shortcut.itemType &&                                   
 512                         modelShortcut.container == shortcut.container &&                                 
 513                         modelShortcut.screenId == shortcut.screenId &&                                   
 514                         modelShortcut.cellX == shortcut.cellX &&                                         
 515                         modelShortcut.cellY == shortcut.cellY &&                                         
 516                         modelShortcut.spanX == shortcut.spanX &&                                         
 517                         modelShortcut.spanY == shortcut.spanY &&                                         
 518                         ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                  
 519                         (modelShortcut.dropPos != null &&                                                
 520                                 shortcut.dropPos != null &&                                              
 521                                 modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                       
 522                         modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                             
 523                     // For all intents and purposes, this is the same object                             
 524                     return;                                                                              
 525                 }                                                                                        
 526             }                                                                                            
 527                                                                                                          
 528             // the modelItem needs to match up perfectly with item if our model is                       
 529             // to be consistent with the database-- for now, just require                                
 530             // modelItem == item or the equality check above                                             
 531             String msg = "item: " + ((item != null) ? item.toString() : "null") +                        
 532                     "modelItem: " +                                                                      
 533                     ((modelItem != null) ? modelItem.toString() : "null") +                              
 534                     "Error: ItemInfo passed to checkItemInfo doesn't match original";                    
 535             RuntimeException e = new RuntimeException(msg);                                              
 536             if (stackTrace != null) {                                                                    
 537                 e.setStackTrace(stackTrace);                                                             
 538             }                                                                                            
 539             throw e;                                                                                     
 540         }                                                                                                
 541     }                                                                                                    
 542                                                                                                          
 543     static void checkItemInfo(final ItemInfo item) {                                                     
 544         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 545         final long itemId = item.id;                                                                     
 546         Runnable r = new Runnable() {                                                                    
 547             public void run() {                                                                          
 548                 synchronized (sBgLock) {                                                                 
 549                     checkItemInfoLocked(itemId, item, stackTrace);                                       
 550                 }                                                                                        
 551             }                                                                                            
 552         };                                                                                               
 553         runOnWorkerThread(r);                                                                            
 554     }                                                                                                    
 555                                                                                                          
 556     static void updateItemInDatabaseHelper(Context context, final ContentValues values,                  
 557             final ItemInfo item, final String callingFunction) {                                         
 558         final long itemId = item.id;                                                                     
 559         final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                         
 560         final ContentResolver cr = context.getContentResolver();                                         
 561                                                                                                          
 562         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 563         Runnable r = new Runnable() {                                                                    
 564             public void run() {                                                                          
 565                 cr.update(uri, values, null, null);                                                      
 566                 updateItemArrays(item, itemId, stackTrace);                                              
 567             }                                                                                            
 568         };                                                                                               
 569         runOnWorkerThread(r);                                                                            
 570     }                                                                                                    
 571                                                                                                          
 572     static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,  
 573             final ArrayList<ItemInfo> items, final String callingFunction) {                             
 574         final ContentResolver cr = context.getContentResolver();                                         
 575                                                                                                          
 576         final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                          
 577         Runnable r = new Runnable() {                                                                    
 578             public void run() {                                                                          
 579                 ArrayList<ContentProviderOperation> ops =                                                
 580                         new ArrayList<ContentProviderOperation>();                                       
 581                 int count = items.size();                                                                
 582                 for (int i = 0; i < count; i++) {                                                        
 583                     ItemInfo item = items.get(i);                                                        
 584                     final long itemId = item.id;                                                         
 585                     final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);             
 586                     ContentValues values = valuesList.get(i);                                            
 587                                                                                                          
 588                     ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());         
 589                     updateItemArrays(item, itemId, stackTrace);                                          
 590                                                                                                          
 591                 }                                                                                        
 592                 try {                                                                                    
 593                     cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                      
 594                 } catch (Exception e) {                                                                  
 595                     e.printStackTrace();                                                                 
 596                 }                                                                                        
 597             }                                                                                            
 598         };                                                                                               
 599         runOnWorkerThread(r);                                                                            
 600     }                                                                                                    
 601                                                                                                          
 602     static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {           
 603         // Lock on mBgLock *after* the db operation                                                      
 604         synchronized (sBgLock) {                                                                         
 605             checkItemInfoLocked(itemId, item, stackTrace);                                               
 606                                                                                                          
 607             if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
 608                     item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                    
 609                 // Item is in a folder, make sure this folder exists                                     
 610                 if (!sBgFolders.containsKey(item.container)) {                                           
 611                     // An items container is being set to a that of an item which is not in              
 612                     // the list of Folders.                                                              
 613                     String msg = "item: " + item + " container being set to: " +                         
 614                             item.container + ", not in the list of folders";                             
 615                     Log.e(TAG, msg);                                                                     
 616                 }                                                                                        
 617             }                                                                                            
 618                                                                                                          
 619             // Items are added/removed from the corresponding FolderInfo elsewhere, such                 
 620             // as in Workspace.onDrop. Here, we just add/remove them from the list of items              
 621             // that are on the desktop, as appropriate                                                   
 622             ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                              
 623             if (modelItem != null &&                                                                     
 624                     (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||              
 625                      modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {             
 626                 switch (modelItem.itemType) {                                                            
 627                     case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                               
 628                     case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                  
 629                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 630                         if (!sBgWorkspaceItems.contains(modelItem)) {                                    
 631                             sBgWorkspaceItems.add(modelItem);                                            
 632                         }                                                                                
 633                         break;                                                                           
 634                     default:                                                                             
 635                         break;                                                                           
 636                 }                                                                                        
 637             } else {                                                                                     
 638                 sBgWorkspaceItems.remove(modelItem);                                                     
 639             }                                                                                            
 640         }                                                                                                
 641     }                                                                                                    
 642                                                                                                          
 643     public void flushWorkerThread() {                                                                    
 644         mFlushingWorkerThread = true;                                                                    
 645         Runnable waiter = new Runnable() {                                                               
 646                 public void run() {                                                                      
 647                     synchronized (this) {                                                                
 648                         notifyAll();                                                                     
 649                         mFlushingWorkerThread = false;                                                   
 650                     }                                                                                    
 651                 }                                                                                        
 652             };                                                                                           
 653                                                                                                          
 654         synchronized(waiter) {                                                                           
 655             runOnWorkerThread(waiter);                                                                   
 656             if (mLoaderTask != null) {                                                                   
 657                 synchronized(mLoaderTask) {                                                              
 658                     mLoaderTask.notify();                                                                
 659                 }                                                                                        
 660             }                                                                                            
 661             boolean success = false;                                                                     
 662             while (!success) {                                                                           
 663                 try {                                                                                    
 664                     waiter.wait();                                                                       
 665                     success = true;                                                                      
 666                 } catch (InterruptedException e) {                                                       
 667                 }                                                                                        
 668             }                                                                                            
 669         }                                                                                                
 670     }                                                                                                    
 671                                                                                                          
 672     /**                                                                                                  
 673      * Move an item in the DB to a new <container, screen, cellX, cellY>                                 
 674      */                                                                                                  
 675     static void moveItemInDatabase(Context context, final ItemInfo item, final long container,           
 676             final long screenId, final int cellX, final int cellY) {                                     
 677         item.container = container;                                                                      
 678         item.cellX = cellX;                                                                              
 679         item.cellY = cellY;                                                                              
 680                                                                                                          
 681         // We store hotseat items in canonical form which is this orientation invariant position         
 682         // in the hotseat                                                                                
 683         if (context instanceof Launcher && screenId < 0 &&                                               
 684                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 685             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 686         } else {                                                                                         
 687             item.screenId = screenId;                                                                    
 688         }                                                                                                
 689                                                                                                          
 690         final ContentValues values = new ContentValues();                                                
 691         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 692         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 693         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 694         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 695                                                                                                          
 696         updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                         
 697     }                                                                                                    
 698                                                                                                          
 699     /**                                                                                                  
 700      * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the               
 701      * cellX, cellY have already been updated on the ItemInfos.                                          
 702      */                                                                                                  
 703     static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                    
 704             final long container, final int screen) {                                                    
 705                                                                                                          
 706         ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                         
 707         int count = items.size();                                                                        
 708                                                                                                          
 709         for (int i = 0; i < count; i++) {                                                                
 710             ItemInfo item = items.get(i);                                                                
 711             item.container = container;                                                                  
 712                                                                                                          
 713             // We store hotseat items in canonical form which is this orientation invariant position     
 714             // in the hotseat                                                                            
 715             if (context instanceof Launcher && screen < 0 &&                                             
 716                     container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                         
 717                 item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,          
 718                         item.cellY);                                                                     
 719             } else {                                                                                     
 720                 item.screenId = screen;                                                                  
 721             }                                                                                            
 722                                                                                                          
 723             final ContentValues values = new ContentValues();                                            
 724             values.put(LauncherSettings.Favorites.CONTAINER, item.container);                            
 725             values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                    
 726             values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                    
 727             values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                
 728                                                                                                          
 729             contentValues.add(values);                                                                   
 730         }                                                                                                
 731         updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                
 732     }                                                                                                    
 733                                                                                                          
 734     /**                                                                                                  
 735      * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>        
 736      */                                                                                                  
 737     static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,         
 738             final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {   
 739         item.container = container;                                                                      
 740         item.cellX = cellX;                                                                              
 741         item.cellY = cellY;                                                                              
 742         item.spanX = spanX;                                                                              
 743         item.spanY = spanY;                                                                              
 744                                                                                                          
 745         // We store hotseat items in canonical form which is this orientation invariant position         
 746         // in the hotseat                                                                                
 747         if (context instanceof Launcher && screenId < 0 &&                                               
 748                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 749             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 750         } else {                                                                                         
 751             item.screenId = screenId;                                                                    
 752         }                                                                                                
 753                                                                                                          
 754         final ContentValues values = new ContentValues();                                                
 755         values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                
 756         values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                        
 757         values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                        
 758         values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                        
 759         values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                        
 760         values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                    
 761                                                                                                          
 762         updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                       
 763     }                                                                                                    
 764                                                                                                          
 765     /**                                                                                                  
 766      * Update an item to the database in a specified container.                                          
 767      */                                                                                                  
 768     static void updateItemInDatabase(Context context, final ItemInfo item) {                             
 769         final ContentValues values = new ContentValues();                                                
 770         item.onAddToDatabase(values);                                                                    
 771         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                
 772         updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                       
 773     }                                                                                                    
 774                                                                                                          
 775     /**                                                                                                  
 776      * Returns true if the shortcuts already exists in the database.                                     
 777      * we identify a shortcut by its title and intent.                                                   
 778      */                                                                                                  
 779     static boolean shortcutExists(Context context, String title, Intent intent) {                        
 780         final ContentResolver cr = context.getContentResolver();                                         
 781         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 782             new String[] { "title", "intent" }, "title=? and intent=?",                                  
 783             new String[] { title, intent.toUri(0) }, null);                                              
 784         boolean result = false;                                                                          
 785         try {                                                                                            
 786             result = c.moveToFirst();                                                                    
 787         } finally {                                                                                      
 788             c.close();                                                                                   
 789         }                                                                                                
 790         return result;                                                                                   
 791     }                                                                                                    
 792                                                                                                          
 793     /**                                                                                                  
 794      * Returns true if the shortcuts already exists in the database.                                     
 795      * we identify a shortcut by the component name of the intent.                                       
 796      */                                                                                                  
 797     static boolean appWasRestored(Context context, Intent intent) {                                      
 798         final ContentResolver cr = context.getContentResolver();                                         
 799         final ComponentName component = intent.getComponent();                                           
 800         if (component == null) {                                                                         
 801             return false;                                                                                
 802         }                                                                                                
 803         String componentName = component.flattenToString();                                              
 804         final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1";       
 805         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                      
 806                 new String[]{"intent", "restored"}, where, null, null);                                  
 807         boolean result = false;                                                                          
 808         try {                                                                                            
 809             result = c.moveToFirst();                                                                    
 810         } finally {                                                                                      
 811             c.close();                                                                                   
 812         }                                                                                                
 813         Log.d(TAG, "shortcutWasRestored is " + result + " for " + componentName);                        
 814         return result;                                                                                   
 815     }                                                                                                    
 816                                                                                                          
 817     /**                                                                                                  
 818      * Returns an ItemInfo array containing all the items in the LauncherModel.                          
 819      * The ItemInfo.id is not set through this function.                                                 
 820      */                                                                                                  
 821     static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {                             
 822         ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                           
 823         final ContentResolver cr = context.getContentResolver();                                         
 824         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {                       
 825                 LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,              
 826                 LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Fav🔵
 827                 LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null); 
 828                                                                                                          
 829         final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);         
 830         final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);        
 831         final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);              
 832         final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                
 833         final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                
 834         final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                
 835         final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                
 836                                                                                                          
 837         try {                                                                                            
 838             while (c.moveToNext()) {                                                                     
 839                 ItemInfo item = new ItemInfo();                                                          
 840                 item.cellX = c.getInt(cellXIndex);                                                       
 841                 item.cellY = c.getInt(cellYIndex);                                                       
 842                 item.spanX = Math.max(1, c.getInt(spanXIndex));                                          
 843                 item.spanY = Math.max(1, c.getInt(spanYIndex));                                          
 844                 item.container = c.getInt(containerIndex);                                               
 845                 item.itemType = c.getInt(itemTypeIndex);                                                 
 846                 item.screenId = c.getInt(screenIndex);                                                   
 847                                                                                                          
 848                 items.add(item);                                                                         
 849             }                                                                                            
 850         } catch (Exception e) {                                                                          
 851             items.clear();                                                                               
 852         } finally {                                                                                      
 853             c.close();                                                                                   
 854         }                                                                                                
 855                                                                                                          
 856         return items;                                                                                    
 857     }                                                                                                    
 858                                                                                                          
 859     /**                                                                                                  
 860      * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.       
 861      */                                                                                                  
 862     FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {            
 863         final ContentResolver cr = context.getContentResolver();                                         
 864         Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                
 865                 "_id=? and (itemType=? or itemType=?)",                                                  
 866                 new String[] { String.valueOf(id),                                                       
 867                         String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);             
 868                                                                                                          
 869         try {                                                                                            
 870             if (c.moveToFirst()) {                                                                       
 871                 final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); 
 872                 final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);        
 873                 final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
 874                 final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);      
 875                 final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);        
 876                 final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);        
 877                                                                                                          
 878                 FolderInfo folderInfo = null;                                                            
 879                 switch (c.getInt(itemTypeIndex)) {                                                       
 880                     case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                    
 881                         folderInfo = findOrMakeFolder(folderList, id);                                   
 882                         break;                                                                           
 883                 }                                                                                        
 884                                                                                                          
 885                 folderInfo.title = c.getString(titleIndex);                                              
 886                 folderInfo.id = id;                                                                      
 887                 folderInfo.container = c.getInt(containerIndex);                                         
 888                 folderInfo.screenId = c.getInt(screenIndex);                                             
 889                 folderInfo.cellX = c.getInt(cellXIndex);                                                 
 890                 folderInfo.cellY = c.getInt(cellYIndex);                                                 
 891                                                                                                          
 892                 return folderInfo;                                                                       
 893             }                                                                                            
 894         } finally {                                                                                      
 895             c.close();                                                                                   
 896         }                                                                                                
 897                                                                                                          
 898         return null;                                                                                     
 899     }                                                                                                    
 900                                                                                                          
 901     /**                                                                                                  
 902      * Add an item to the database in a specified container. Sets the container, screen, cellX and       
 903      * cellY fields of the item. Also assigns an ID to the item.                                         
 904      */                                                                                                  
 905     static void addItemToDatabase(Context context, final ItemInfo item, final long container,            
 906             final long screenId, final int cellX, final int cellY, final boolean notify) {               
 907         item.container = container;                                                                      
 908         item.cellX = cellX;                                                                              
 909         item.cellY = cellY;                                                                              
 910         // We store hotseat items in canonical form which is this orientation invariant position         
 911         // in the hotseat                                                                                
 912         if (context instanceof Launcher && screenId < 0 &&                                               
 913                 container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 914             item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);           
 915         } else {                                                                                         
 916             item.screenId = screenId;                                                                    
 917         }                                                                                                
 918                                                                                                          
 919         final ContentValues values = new ContentValues();                                                
 920         final ContentResolver cr = context.getContentResolver();                                         
 921         item.onAddToDatabase(values);                                                                    
 922                                                                                                          
 923         item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                            
 924         values.put(LauncherSettings.Favorites._ID, item.id);                                             
 925         item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                
 926                                                                                                          
 927         Runnable r = new Runnable() {                                                                    
 928             public void run() {                                                                          
 929                 cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                              
 930                         LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                 
 931                                                                                                          
 932                 // Lock on mBgLock *after* the db operation                                              
 933                 synchronized (sBgLock) {                                                                 
 934                     checkItemInfoLocked(item.id, item, null);                                            
 935                     sBgItemsIdMap.put(item.id, item);                                                    
 936                     switch (item.itemType) {                                                             
 937                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
 938                             sBgFolders.put(item.id, (FolderInfo) item);                                  
 939                             // Fall through                                                              
 940                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
 941                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
 942                             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||        
 943                                     item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {    
 944                                 sBgWorkspaceItems.add(item);                                             
 945                             } else {                                                                     
 946                                 if (!sBgFolders.containsKey(item.container)) {                           
 947                                     // Adding an item to a folder that doesn't exist.                    
 948                                     String msg = "adding item: " + item + " to a folder that " +         
 949                                             " doesn't exist";                                            
 950                                     Log.e(TAG, msg);                                                     
 951                                 }                                                                        
 952                             }                                                                            
 953                             break;                                                                       
 954                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
 955                             sBgAppWidgets.add((LauncherAppWidgetInfo) item);                             
 956                             break;                                                                       
 957                     }                                                                                    
 958                 }                                                                                        
 959             }                                                                                            
 960         };                                                                                               
 961         runOnWorkerThread(r);                                                                            
 962     }                                                                                                    
 963                                                                                                          
 964     /**                                                                                                  
 965      * Creates a new unique child id, for a given cell span across all layouts.                          
 966      */                                                                                                  
 967     static int getCellLayoutChildId(                                                                     
 968             long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {         
 969         return (((int) container & 0xFF) << 24)                                                          
 970                 | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);          
 971     }                                                                                                    
 972                                                                                                          
 973     /**                                                                                                  
 974      * Removes the specified item from the database                                                      
 975      * @param context                                                                                    
 976      * @param item                                                                                       
 977      */                                                                                                  
 978     static void deleteItemFromDatabase(Context context, final ItemInfo item) {                           
 979         final ContentResolver cr = context.getContentResolver();                                         
 980         final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);                
 981                                                                                                          
 982         Runnable r = new Runnable() {                                                                    
 983             public void run() {                                                                          
 984                 cr.delete(uriToDelete, null, null);                                                      
 985                                                                                                          
 986                 // Lock on mBgLock *after* the db operation                                              
 987                 synchronized (sBgLock) {                                                                 
 988                     switch (item.itemType) {                                                             
 989                         case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                
 990                             sBgFolders.remove(item.id);                                                  
 991                             for (ItemInfo info: sBgItemsIdMap.values()) {                                
 992                                 if (info.container == item.id) {                                         
 993                                     // We are deleting a folder which still contains items that          
 994                                     // think they are contained by that folder.                          
 995                                     String msg = "deleting a folder (" + item + ") which still " +       
 996                                             "contains items (" + info + ")";                             
 997                                     Log.e(TAG, msg);                                                     
 998                                 }                                                                        
 999                             }                                                                            
1000                             sBgWorkspaceItems.remove(item);                                              
1001                             break;                                                                       
1002                         case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                           
1003                         case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                              
1004                             sBgWorkspaceItems.remove(item);                                              
1005                             break;                                                                       
1006                         case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                             
1007                             sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                          
1008                             break;                                                                       
1009                     }                                                                                    
1010                     sBgItemsIdMap.remove(item.id);                                                       
1011                     sBgDbIconCache.remove(item);                                                         
1012                 }                                                                                        
1013             }                                                                                            
1014         };                                                                                               
1015         runOnWorkerThread(r);                                                                            
1016     }                                                                                                    
1017                                                                                                          
1018     /**                                                                                                  
1019      * Update the order of the workspace screens in the database. The array list contains                
1020      * a list of screen ids in the order that they should appear.                                        
1021      */                                                                                                  
1022     void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                    
1023         // Log to disk                                                                                   
1024         Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                       
1025         Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);        
1026                                                                                                          
1027         final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                
1028         final ContentResolver cr = context.getContentResolver();                                         
1029         final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                   
1030                                                                                                          
1031         // Remove any negative screen ids -- these aren't persisted                                      
1032         Iterator<Long> iter = screensCopy.iterator();                                                    
1033         while (iter.hasNext()) {                                                                         
1034             long id = iter.next();                                                                       
1035             if (id < 0) {                                                                                
1036                 iter.remove();                                                                           
1037             }                                                                                            
1038         }                                                                                                
1039                                                                                                          
1040         Runnable r = new Runnable() {                                                                    
1041             @Override                                                                                    
1042             public void run() {                                                                          
1043                 // Clear the table                                                                       
1044                 cr.delete(uri, null, null);                                                              
1045                 int count = screensCopy.size();                                                          
1046                 ContentValues[] values = new ContentValues[count];                                       
1047                 for (int i = 0; i < count; i++) {                                                        
1048                     ContentValues v = new ContentValues();                                               
1049                     long screenId = screensCopy.get(i);                                                  
1050                     v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                              
1051                     v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                             
1052                     values[i] = v;                                                                       
1053                 }                                                                                        
1054                 cr.bulkInsert(uri, values);                                                              
1055                                                                                                          
1056                 synchronized (sBgLock) {                                                                 
1057                     sBgWorkspaceScreens.clear();                                                         
1058                     sBgWorkspaceScreens.addAll(screensCopy);                                             
1059                 }                                                                                        
1060             }                                                                                            
1061         };                                                                                               
1062         runOnWorkerThread(r);                                                                            
1063     }                                                                                                    
1064                                                                                                          
1065     /**                                                                                                  
1066      * Remove the contents of the specified folder from the database                                     
1067      */                                                                                                  
1068     static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {               
1069         final ContentResolver cr = context.getContentResolver();                                         
1070                                                                                                          
1071         Runnable r = new Runnable() {                                                                    
1072             public void run() {                                                                          
1073                 cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);         
1074                 // Lock on mBgLock *after* the db operation                                              
1075                 synchronized (sBgLock) {                                                                 
1076                     sBgItemsIdMap.remove(info.id);                                                       
1077                     sBgFolders.remove(info.id);                                                          
1078                     sBgDbIconCache.remove(info);                                                         
1079                     sBgWorkspaceItems.remove(info);                                                      
1080                 }                                                                                        
1081                                                                                                          
1082                 cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                        
1083                         LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                     
1084                 // Lock on mBgLock *after* the db operation                                              
1085                 synchronized (sBgLock) {                                                                 
1086                     for (ItemInfo childInfo : info.contents) {                                           
1087                         sBgItemsIdMap.remove(childInfo.id);                                              
1088                         sBgDbIconCache.remove(childInfo);                                                
1089                     }                                                                                    
1090                 }                                                                                        
1091             }                                                                                            
1092         };                                                                                               
1093         runOnWorkerThread(r);                                                                            
1094     }                                                                                                    
1095                                                                                                          
1096     /**                                                                                                  
1097      * Set this as the current Launcher activity object for the loader.                                  
1098      */                                                                                                  
1099     public void initialize(Callbacks callbacks) {                                                        
1100         synchronized (mLock) {                                                                           
1101             mCallbacks = new WeakReference<Callbacks>(callbacks);                                        
1102         }                                                                                                
1103     }                                                                                                    
1104                                                                                                          
1105     /**                                                                                                  
1106      * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                        
1107      * ACTION_PACKAGE_CHANGED.                                                                           
1108      */                                                                                                  
1109     @Override                                                                                            
1110     public void onReceive(Context context, Intent intent) {                                              
1111         if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);                                     
1112                                                                                                          
1113         final String action = intent.getAction();                                                        
1114                                                                                                          
1115         if (Intent.ACTION_PACKAGE_CHANGED.equals(action)                                                 
1116                 || Intent.ACTION_PACKAGE_REMOVED.equals(action)                                          
1117                 || Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                         
1118             final String packageName = intent.getData().getSchemeSpecificPart();                         
1119             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1120                                                                                                          
1121             int op = PackageUpdatedTask.OP_NONE;                                                         
1122                                                                                                          
1123             if (packageName == null || packageName.length() == 0) {                                      
1124                 // they sent us a bad intent                                                             
1125                 return;                                                                                  
1126             }                                                                                            
1127                                                                                                          
1128             if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {                                          
1129                 op = PackageUpdatedTask.OP_UPDATE;                                                       
1130             } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {                                   
1131                 if (!replacing) {                                                                        
1132                     op = PackageUpdatedTask.OP_REMOVE;                                                   
1133                 }                                                                                        
1134                 // else, we are replacing the package, so a PACKAGE_ADDED will be sent                   
1135                 // later, we will update the package at this time                                        
1136             } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                     
1137                 if (!replacing) {                                                                        
1138                     op = PackageUpdatedTask.OP_ADD;                                                      
1139                 } else {                                                                                 
1140                     op = PackageUpdatedTask.OP_UPDATE;                                                   
1141                 }                                                                                        
1142             }                                                                                            
1143                                                                                                          
1144             if (op != PackageUpdatedTask.OP_NONE) {                                                      
1145                 enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));         
1146             }                                                                                            
1147                                                                                                          
1148         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {                       
1149             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1150             String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);           
1151             if (!replacing) {                                                                            
1152                 enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));      
1153                 if (mAppsCanBeOnRemoveableStorage) {                                                     
1154                     // Only rebind if we support removable storage.  It catches the case where           
1155                     // apps on the external sd card need to be reloaded                                  
1156                     startLoaderFromBackground();                                                         
1157                 }                                                                                        
1158             } else {                                                                                     
1159                 // If we are replacing then just update the packages in the list                         
1160                 enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,               
1161                         packages));                                                                      
1162             }                                                                                            
1163         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {                     
1164             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);             
1165             if (!replacing) {                                                                            
1166                 String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);       
1167                 enqueuePackageUpdated(new PackageUpdatedTask(                                            
1168                             PackageUpdatedTask.OP_UNAVAILABLE, packages));                               
1169             }                                                                                            
1170             // else, we are replacing the packages, so ignore this event and wait for                    
1171             // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time                       
1172         } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                        
1173             // If we have changed locale we need to clear out the labels in all apps/workspace.          
1174             forceReload();                                                                               
1175         } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                 
1176              // Check if configuration change was an mcc/mnc change which would affect app resources     
1177              // and we would need to clear out the labels in all apps/workspace. Same handling as        
1178              // above for ACTION_LOCALE_CHANGED                                                          
1179              Configuration currentConfig = context.getResources().getConfiguration();                    
1180              if (mPreviousConfigMcc != currentConfig.mcc) {                                              
1181                    Log.d(TAG, "Reload apps on config change. curr_mcc:"                                  
1182                        + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                          
1183                    forceReload();                                                                        
1184              }                                                                                           
1185              // Update previousConfig                                                                    
1186              mPreviousConfigMcc = currentConfig.mcc;                                                     
1187         } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                 
1188                    SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                     
1189             if (mCallbacks != null) {                                                                    
1190                 Callbacks callbacks = mCallbacks.get();                                                  
1191                 if (callbacks != null) {                                                                 
1192                     callbacks.bindSearchablesChanged();                                                  
1193                 }                                                                                        
1194             }                                                                                            
1195         }                                                                                                
1196     }                                                                                                    
1197                                                                                                          
1198     private void forceReload() {                                                                         
1199         resetLoadedState(true, true);                                                                    
1200                                                                                                          
1201         // Do this here because if the launcher activity is running it will be restarted.                
1202         // If it's not running startLoaderFromBackground will merely tell it that it needs               
1203         // to reload.                                                                                    
1204         startLoaderFromBackground();                                                                     
1205     }                                                                                                    
1206                                                                                                          
1207     public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {             
1208         synchronized (mLock) {                                                                           
1209             // Stop any existing loaders first, so they don't set mAllAppsLoaded or                      
1210             // mWorkspaceLoaded to true later                                                            
1211             stopLoaderLocked();                                                                          
1212             if (resetAllAppsLoaded) mAllAppsLoaded = false;                                              
1213             if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                          
1214         }                                                                                                
1215     }                                                                                                    
1216                                                                                                          
1217     /**                                                                                                  
1218      * When the launcher is in the background, it's possible for it to miss paired                       
1219      * configuration changes.  So whenever we trigger the loader from the background                     
1220      * tell the launcher that it needs to re-run the loader when it comes back instead                   
1221      * of doing it now.                                                                                  
1222      */                                                                                                  
1223     public void startLoaderFromBackground() {                                                            
1224         boolean runLoader = false;                                                                       
1225         if (mCallbacks != null) {                                                                        
1226             Callbacks callbacks = mCallbacks.get();                                                      
1227             if (callbacks != null) {                                                                     
1228                 // Only actually run the loader if they're not paused.                                   
1229                 if (!callbacks.setLoadOnResume()) {                                                      
1230                     runLoader = true;                                                                    
1231                 }                                                                                        
1232             }                                                                                            
1233         }                                                                                                
1234         if (runLoader) {                                                                                 
1235             startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                          
1236         }                                                                                                
1237     }                                                                                                    
1238                                                                                                          
1239     // If there is already a loader task running, tell it to stop.                                       
1240     // returns true if isLaunching() was true on the old task                                            
1241     private boolean stopLoaderLocked() {                                                                 
1242         boolean isLaunching = false;                                                                     
1243         LoaderTask oldTask = mLoaderTask;                                                                
1244         if (oldTask != null) {                                                                           
1245             if (oldTask.isLaunching()) {                                                                 
1246                 isLaunching = true;                                                                      
1247             }                                                                                            
1248             oldTask.stopLocked();                                                                        
1249         }                                                                                                
1250         return isLaunching;                                                                              
1251     }                                                                                                    
1252                                                                                                          
1253     public void startLoader(boolean isLaunching, int synchronousBindPage) {                              
1254         startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                 
1255     }                                                                                                    
1256                                                                                                          
1257     public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {               
1258         synchronized (mLock) {                                                                           
1259             if (DEBUG_LOADERS) {                                                                         
1260                 Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                    
1261             }                                                                                            
1262                                                                                                          
1263             // Clear any deferred bind-runnables from the synchronized load process                      
1264             // We must do this before any loading/binding is scheduled below.                            
1265             mDeferredBindRunnables.clear();                                                              
1266                                                                                                          
1267             // Don't bother to start the thread if we know it's not going to do anything                 
1268             if (mCallbacks != null && mCallbacks.get() != null) {                                        
1269                 // If there is already one running, tell it to stop.                                     
1270                 // also, don't downgrade isLaunching if we're already running                            
1271                 isLaunching = isLaunching || stopLoaderLocked();                                         
1272                 mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                 
1273                 if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                
1274                         && mAllAppsLoaded && mWorkspaceLoaded) {                                         
1275                     mLoaderTask.runBindSynchronousPage(synchronousBindPage);                             
1276                 } else {                                                                                 
1277                     sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                     
1278                     sWorker.post(mLoaderTask);                                                           
1279                 }                                                                                        
1280             }                                                                                            
1281         }                                                                                                
1282     }                                                                                                    
1283                                                                                                          
1284     void bindRemainingSynchronousPages() {                                                               
1285         // Post the remaining side pages to be loaded                                                    
1286         if (!mDeferredBindRunnables.isEmpty()) {                                                         
1287             for (final Runnable r : mDeferredBindRunnables) {                                            
1288                 mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                          
1289             }                                                                                            
1290             mDeferredBindRunnables.clear();                                                              
1291         }                                                                                                
1292     }                                                                                                    
1293                                                                                                          
1294     public void stopLoader() {                                                                           
1295         synchronized (mLock) {                                                                           
1296             if (mLoaderTask != null) {                                                                   
1297                 mLoaderTask.stopLocked();                                                                
1298             }                                                                                            
1299         }                                                                                                
1300     }                                                                                                    
1301                                                                                                          
1302     /** Loads the workspace screens db into a map of Rank -> ScreenId */                                 
1303     private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {                      
1304         final ContentResolver contentResolver = context.getContentResolver();                            
1305         final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                            
1306         final Cursor sc = contentResolver.query(screensUri, null, null, null, null);                     
1307         TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();                            
1308                                                                                                          
1309         try {                                                                                            
1310             final int idIndex = sc.getColumnIndexOrThrow(                                                
1311                     LauncherSettings.WorkspaceScreens._ID);                                              
1312             final int rankIndex = sc.getColumnIndexOrThrow(                                              
1313                     LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                      
1314             while (sc.moveToNext()) {                                                                    
1315                 try {                                                                                    
1316                     long screenId = sc.getLong(idIndex);                                                 
1317                     int rank = sc.getInt(rankIndex);                                                     
1318                     orderedScreens.put(rank, screenId);                                                  
1319                 } catch (Exception e) {                                                                  
1320                     Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e,🔵
1321                 }                                                                                        
1322             }                                                                                            
1323         } finally {                                                                                      
1324             sc.close();                                                                                  
1325         }                                                                                                
1326                                                                                                          
1327         // Log to disk                                                                                   
1328         Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);                           
1329         ArrayList<String> orderedScreensPairs= new ArrayList<String>();                                  
1330         for (Integer i : orderedScreens.keySet()) {                                                      
1331             orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");                     
1332         }                                                                                                
1333         Launcher.addDumpLog(TAG, "11683562 -   screens: " +                                              
1334                 TextUtils.join(", ", orderedScreensPairs), true);                                        
1335         return orderedScreens;                                                                           
1336     }                                                                                                    
1337                                                                                                          
1338     public boolean isAllAppsLoaded() {                                                                   
1339         return mAllAppsLoaded;                                                                           
1340     }                                                                                                    
1341                                                                                                          
1342     boolean isLoadingWorkspace() {                                                                       
1343         synchronized (mLock) {                                                                           
1344             if (mLoaderTask != null) {                                                                   
1345                 return mLoaderTask.isLoadingWorkspace();                                                 
1346             }                                                                                            
1347         }                                                                                                
1348         return false;                                                                                    
1349     }                                                                                                    
1350                                                                                                          
1351     /**                                                                                                  
1352      * Runnable for the thread that loads the contents of the launcher:                                  
1353      *   - workspace icons                                                                               
1354      *   - widgets                                                                                       
1355      *   - all apps icons                                                                                
1356      */                                                                                                  
1357     private class LoaderTask implements Runnable {                                                       
1358         private Context mContext;                                                                        
1359                                                                                                          
1360         private boolean mIsLaunching;                                                                    
1361                                                                                                          
1362         private boolean mIsLoadingAndBindingWorkspace;                                                   
1363                                                                                                          
1364         private boolean mStopped;                                                                        
1365                                                                                                          
1366         private boolean mLoadAndBindStepFinished;                                                        
1367                                                                                                          
1368         private int mFlags;                                                                              
1369                                                                                                          
1370         private HashMap<Object, CharSequence> mLabelCache;                                               
1371                                                                                                          
1372         LoaderTask(Context context, boolean isLaunching, int flags) {                                    
1373             mContext = context;                                                                          
1374             mIsLaunching = isLaunching;                                                                  
1375             mLabelCache = new HashMap<Object, CharSequence>();                                           
1376             mFlags = flags;                                                                              
1377         }                                                                                                
1378                                                                                                          
1379         boolean isLaunching() {                                                                          
1380             return mIsLaunching;                                                                         
1381         }                                                                                                
1382                                                                                                          
1383         boolean isLoadingWorkspace() {                                                                   
1384             return mIsLoadingAndBindingWorkspace;                                                        
1385         }                                                                                                
1386                                                                                                          
1387         /** Returns whether this is an upgrade path */                                                   
1388         private boolean loadAndBindWorkspace() {                                                         
1389             mIsLoadingAndBindingWorkspace = true;                                                        
1390                                                                                                          
1391             // Load the workspace                                                                        
1392             if (DEBUG_LOADERS) {                                                                         
1393                 Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                 
1394             }                                                                                            
1395                                                                                                          
1396             boolean isUpgradePath = false;                                                               
1397             if (!mWorkspaceLoaded) {                                                                     
1398                 isUpgradePath = loadWorkspace();                                                         
1399                 synchronized (LoaderTask.this) {                                                         
1400                     if (mStopped) {                                                                      
1401                         return isUpgradePath;                                                            
1402                     }                                                                                    
1403                     mWorkspaceLoaded = true;                                                             
1404                 }                                                                                        
1405             }                                                                                            
1406                                                                                                          
1407             // Bind the workspace                                                                        
1408             bindWorkspace(-1, isUpgradePath);                                                            
1409             return isUpgradePath;                                                                        
1410         }                                                                                                
1411                                                                                                          
1412         private void waitForIdle() {                                                                     
1413             // Wait until the either we're stopped or the other threads are done.                        
1414             // This way we don't start loading all apps until the workspace has settled                  
1415             // down.                                                                                     
1416             synchronized (LoaderTask.this) {                                                             
1417                 final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;           
1418                                                                                                          
1419                 mHandler.postIdle(new Runnable() {                                                       
1420                         public void run() {                                                              
1421                             synchronized (LoaderTask.this) {                                             
1422                                 mLoadAndBindStepFinished = true;                                         
1423                                 if (DEBUG_LOADERS) {                                                     
1424                                     Log.d(TAG, "done with previous binding step");                       
1425                                 }                                                                        
1426                                 LoaderTask.this.notify();                                                
1427                             }                                                                            
1428                         }                                                                                
1429                     });                                                                                  
1430                                                                                                          
1431                 while (!mStopped && !mLoadAndBindStepFinished && !mFlushingWorkerThread) {               
1432                     try {                                                                                
1433                         // Just in case mFlushingWorkerThread changes but we aren't woken up,            
1434                         // wait no longer than 1sec at a time                                            
1435                         this.wait(1000);                                                                 
1436                     } catch (InterruptedException ex) {                                                  
1437                         // Ignore                                                                        
1438                     }                                                                                    
1439                 }                                                                                        
1440                 if (DEBUG_LOADERS) {                                                                     
1441                     Log.d(TAG, "waited "                                                                 
1442                             + (SystemClock.uptimeMillis()-workspaceWaitTime)                             
1443                             + "ms for previous step to finish binding");                                 
1444                 }                                                                                        
1445             }                                                                                            
1446         }                                                                                                
1447                                                                                                          
1448         void runBindSynchronousPage(int synchronousBindPage) {                                           
1449             if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                 
1450                 // Ensure that we have a valid page index to load synchronously                          
1451                 throw new RuntimeException("Should not call runBindSynchronousPage() without " +         
1452                         "valid page index");                                                             
1453             }                                                                                            
1454             if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                  
1455                 // Ensure that we don't try and bind a specified page when the pages have not been       
1456                 // loaded already (we should load everything asynchronously in that case)                
1457                 throw new RuntimeException("Expecting AllApps and Workspace to be loaded");              
1458             }                                                                                            
1459             synchronized (mLock) {                                                                       
1460                 if (mIsLoaderTaskRunning) {                                                              
1461                     // Ensure that we are never running the background loading at this point since       
1462                     // we also touch the background collections                                          
1463                     throw new RuntimeException("Error! Background loading is already running");          
1464                 }                                                                                        
1465             }                                                                                            
1466                                                                                                          
1467             // XXX: Throw an exception if we are already loading (since we touch the worker thread       
1468             //      data structures, we can't allow any other thread to touch that data, but because     
1469             //      this call is synchronous, we can get away with not locking).                         
1470                                                                                                          
1471             // The LauncherModel is static in the LauncherAppState and mHandler may have queued          
1472             // operations from the previous activity.  We need to ensure that all queued operations      
1473             // are executed before any synchronous binding work is done.                                 
1474             mHandler.flush();                                                                            
1475                                                                                                          
1476             // Divide the set of loaded items into those that we are binding synchronously, and          
1477             // everything else that is to be bound normally (asynchronously).                            
1478             bindWorkspace(synchronousBindPage, false);                                                   
1479             // XXX: For now, continue posting the binding of AllApps as there are other issues that      
1480             //      arise from that.                                                                     
1481             onlyBindAllApps();                                                                           
1482         }                                                                                                
1483                                                                                                          
1484         public void run() {                                                                              
1485             boolean isUpgrade = false;                                                                   
1486                                                                                                          
1487             synchronized (mLock) {                                                                       
1488                 mIsLoaderTaskRunning = true;                                                             
1489             }                                                                                            
1490             // Optimize for end-user experience: if the Launcher is up and // running with the           
1491             // All Apps interface in the foreground, load All Apps first. Otherwise, load the            
1492             // workspace first (default).                                                                
1493             keep_running: {                                                                              
1494                 // Elevate priority when Home launches for the first time to avoid                       
1495                 // starving at boot time. Staring at a blank home is not cool.                           
1496                 synchronized (mLock) {                                                                   
1497                     if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                        
1498                             (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                  
1499                     android.os.Process.setThreadPriority(mIsLaunching                                    
1500                             ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);     
1501                 }                                                                                        
1502                 if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                              
1503                 isUpgrade = loadAndBindWorkspace();                                                      
1504                                                                                                          
1505                 if (mStopped) {                                                                          
1506                     break keep_running;                                                                  
1507                 }                                                                                        
1508                                                                                                          
1509                 // Whew! Hard work done.  Slow us down, and wait until the UI thread has                 
1510                 // settled down.                                                                         
1511                 synchronized (mLock) {                                                                   
1512                     if (mIsLaunching) {                                                                  
1513                         if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");          
1514                         android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);        
1515                     }                                                                                    
1516                 }                                                                                        
1517                 waitForIdle();                                                                           
1518                                                                                                          
1519                 // second step                                                                           
1520                 if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                               
1521                 loadAndBindAllApps();                                                                    
1522                                                                                                          
1523                 // Restore the default thread priority after we are done loading items                   
1524                 synchronized (mLock) {                                                                   
1525                     android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);               
1526                 }                                                                                        
1527             }                                                                                            
1528                                                                                                          
1529             // Update the saved icons if necessary                                                       
1530             if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                   
1531             synchronized (sBgLock) {                                                                     
1532                 for (Object key : sBgDbIconCache.keySet()) {                                             
1533                     updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));              
1534                 }                                                                                        
1535                 sBgDbIconCache.clear();                                                                  
1536             }                                                                                            
1537                                                                                                          
1538             if (LauncherAppState.isDisableAllApps()) {                                                   
1539                 // Ensure that all the applications that are in the system are                           
1540                 // represented on the home screen.                                                       
1541                 if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {                                       
1542                     verifyApplications();                                                                
1543                 }                                                                                        
1544             }                                                                                            
1545                                                                                                          
1546             // Clear out this reference, otherwise we end up holding it until all of the                 
1547             // callback runnables are done.                                                              
1548             mContext = null;                                                                             
1549                                                                                                          
1550             synchronized (mLock) {                                                                       
1551                 // If we are still the last one to be scheduled, remove ourselves.                       
1552                 if (mLoaderTask == this) {                                                               
1553                     mLoaderTask = null;                                                                  
1554                 }                                                                                        
1555                 mIsLoaderTaskRunning = false;                                                            
1556             }                                                                                            
1557         }                                                                                                
1558                                                                                                          
1559         public void stopLocked() {                                                                       
1560             synchronized (LoaderTask.this) {                                                             
1561                 mStopped = true;                                                                         
1562                 this.notify();                                                                           
1563             }                                                                                            
1564         }                                                                                                
1565                                                                                                          
1566         /**                                                                                              
1567          * Gets the callbacks object.  If we've been stopped, or if the launcher object                  
1568          * has somehow been garbage collected, return null instead.  Pass in the Callbacks               
1569          * object that was around when the deferred message was scheduled, and if there's                
1570          * a new Callbacks object around then also return null.  This will save us from                  
1571          * calling onto it with data that will be ignored.                                               
1572          */                                                                                              
1573         Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                              
1574             synchronized (mLock) {                                                                       
1575                 if (mStopped) {                                                                          
1576                     return null;                                                                         
1577                 }                                                                                        
1578                                                                                                          
1579                 if (mCallbacks == null) {                                                                
1580                     return null;                                                                         
1581                 }                                                                                        
1582                                                                                                          
1583                 final Callbacks callbacks = mCallbacks.get();                                            
1584                 if (callbacks != oldCallbacks) {                                                         
1585                     return null;                                                                         
1586                 }                                                                                        
1587                 if (callbacks == null) {                                                                 
1588                     Log.w(TAG, "no mCallbacks");                                                         
1589                     return null;                                                                         
1590                 }                                                                                        
1591                                                                                                          
1592                 return callbacks;                                                                        
1593             }                                                                                            
1594         }                                                                                                
1595                                                                                                          
1596         private void verifyApplications() {                                                              
1597             final Context context = mApp.getContext();                                                   
1598             // Cross reference all the applications in our apps list with items in the workspace         
1599             ArrayList<ItemInfo> tmpInfos;                                                                
1600             ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                       
1601             synchronized(sBgLock) {                                                                      
1602                 for (AppInfo app : mBgAllAppsList.data) {                                                
1603                     tmpInfos = getItemInfoForComponentName(app.componentName);                           
1604                     if (tmpInfos.isEmpty()) {                                                            
1605                         // We are missing an application icon, so add this to the workspace              
1606                         added.add(app);                                                                  
1607                         // This is a rare event, so lets log it                                          
1608                         Log.e(TAG, "Missing Application on load: " + app);                               
1609                     }                                                                                    
1610                 }                                                                                        
1611             }                                                                                            
1612             if (!added.isEmpty()) {                                                                      
1613                 Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;                           
1614                 addAndBindAddedApps(context, added, cb, new ArrayList<AppInfo>());                       
1615             }                                                                                            
1616         }                                                                                                
1617                                                                                                          
1618         // check & update map of what's occupied; used to discard overlapping/invalid items              
1619         private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item,          
1620                                            AtomicBoolean deleteOnInvalidPlacement) {                     
1621             LauncherAppState app = LauncherAppState.getInstance();                                       
1622             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1623             final int countX = (int) grid.numColumns;                                                    
1624             final int countY = (int) grid.numRows;                                                       
1625                                                                                                          
1626             long containerIndex = item.screenId;                                                         
1627             if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                        
1628                 // Return early if we detect that an item is under the hotseat button                    
1629                 if (mCallbacks == null ||                                                                
1630                         mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                     
1631                     deleteOnInvalidPlacement.set(true);                                                  
1632                     Log.e(TAG, "Error loading shortcut into hotseat " + item                             
1633                             + " into position (" + item.screenId + ":" + item.cellX + ","                
1634                             + item.cellY + ") occupied by all apps");                                    
1635                     return false;                                                                        
1636                 }                                                                                        
1637                                                                                                          
1638                 final ItemInfo[][] hotseatItems =                                                        
1639                         occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);               
1640                                                                                                          
1641                 if (item.screenId >= grid.numHotseatIcons) {                                             
1642                     Log.e(TAG, "Error loading shortcut " + item                                          
1643                             + " into hotseat position " + item.screenId                                  
1644                             + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)            
1645                             + ")");                                                                      
1646                     return false;                                                                        
1647                 }                                                                                        
1648                                                                                                          
1649                 if (hotseatItems != null) {                                                              
1650                     if (hotseatItems[(int) item.screenId][0] != null) {                                  
1651                         Log.e(TAG, "Error loading shortcut into hotseat " + item                         
1652                                 + " into position (" + item.screenId + ":" + item.cellX + ","            
1653                                 + item.cellY + ") occupied by "                                          
1654                                 + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)             
1655                                 [(int) item.screenId][0]);                                               
1656                             return false;                                                                
1657                     } else {                                                                             
1658                         hotseatItems[(int) item.screenId][0] = item;                                     
1659                         return true;                                                                     
1660                     }                                                                                    
1661                 } else {                                                                                 
1662                     final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];              
1663                     items[(int) item.screenId][0] = item;                                                
1664                     occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);            
1665                     return true;                                                                         
1666                 }                                                                                        
1667             } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                 
1668                 // Skip further checking if it is not the hotseat or workspace container                 
1669                 return true;                                                                             
1670             }                                                                                            
1671                                                                                                          
1672             if (!occupied.containsKey(item.screenId)) {                                                  
1673                 ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                               
1674                 occupied.put(item.screenId, items);                                                      
1675             }                                                                                            
1676                                                                                                          
1677             final ItemInfo[][] screens = occupied.get(item.screenId);                                    
1678             if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                        
1679                     item.cellX < 0 || item.cellY < 0 ||                                                  
1680                     item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {              
1681                 Log.e(TAG, "Error loading shortcut " + item                                              
1682                         + " into cell (" + containerIndex + "-" + item.screenId + ":"                    
1683                         + item.cellX + "," + item.cellY                                                  
1684                         + ") out of screen bounds ( " + countX + "x" + countY + ")");                    
1685                 return false;                                                                            
1686             }                                                                                            
1687                                                                                                          
1688             // Check if any workspace icons overlap with each other                                      
1689             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1690                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1691                     if (screens[x][y] != null) {                                                         
1692                         Log.e(TAG, "Error loading shortcut " + item                                      
1693                             + " into cell (" + containerIndex + "-" + item.screenId + ":"                
1694                             + x + "," + y                                                                
1695                             + ") occupied by "                                                           
1696                             + screens[x][y]);                                                            
1697                         return false;                                                                    
1698                     }                                                                                    
1699                 }                                                                                        
1700             }                                                                                            
1701             for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                 
1702                 for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                             
1703                     screens[x][y] = item;                                                                
1704                 }                                                                                        
1705             }                                                                                            
1706                                                                                                          
1707             return true;                                                                                 
1708         }                                                                                                
1709                                                                                                          
1710         /** Clears all the sBg data structures */                                                        
1711         private void clearSBgDataStructures() {                                                          
1712             synchronized (sBgLock) {                                                                     
1713                 sBgWorkspaceItems.clear();                                                               
1714                 sBgAppWidgets.clear();                                                                   
1715                 sBgFolders.clear();                                                                      
1716                 sBgItemsIdMap.clear();                                                                   
1717                 sBgDbIconCache.clear();                                                                  
1718                 sBgWorkspaceScreens.clear();                                                             
1719             }                                                                                            
1720         }                                                                                                
1721                                                                                                          
1722         /** Returns whether this is an upgrade path */                                                   
1723         private boolean loadWorkspace() {                                                                
1724             // Log to disk                                                                               
1725             Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                
1726             final long t = (DEBUG_LOADERS) ? SystemClock.uptimeMillis() : 0;                             
1727             final Context context = mContext;                                                            
1728             final ContentResolver contentResolver = context.getContentResolver();                        
1729             final PackageManager manager = context.getPackageManager();                                  
1730             final AppWidgetManager widgets = AppWidgetManager.getInstance(context);                      
1731             final boolean isSafeMode = manager.isSafeMode();                                             
1732             LauncherAppState app = LauncherAppState.getInstance();                                       
1733             DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                
1734             int countX = ((int) (grid.numColumns));                                                      
1735             int countY = ((int) (grid.numRows));                                                         
1736             if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                           
1737                 Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);            
1738                 LauncherAppState.getLauncherProvider().deleteDatabase();                                 
1739             }                                                                                            
1740             if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                         
1741                 // append the user's Launcher2 shortcuts                                                 
1742                 Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);               
1743                 LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                      
1744             } else {                                                                                     
1745                 // Make sure the default workspace is loaded                                             
1746                 Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);             
1747                 LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);               
1748             }                                                                                            
1749             // Check if we need to do any upgrade-path logic                                             
1750             // (Includes having just imported default favorites)                                         
1751             boolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb();              
1752             // Log to disk                                                                               
1753             Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);                  
1754             synchronized(sBgLock) {                                                                      
1755                 clearSBgDataStructures();                                                                
1756                 final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                             
1757                 final ArrayList<Long> restoredRows = new ArrayList<Long>();                              
1758                 final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                           
1759                 if (DEBUG_LOADERS) {                                                                     
1760                     Log.d(TAG, "loading model from " + contentUri);                                      
1761                 }                                                                                        
1762                 final Cursor c = contentResolver.query(contentUri, null, null, null, null);              
1763                 // +1 for the hotseat (it can be larger than the workspace)                              
1764                 // Load workspace in reverse order to ensure that latest items are loaded first (and     
1765                 // before any earlier duplicates)                                                        
1766                 final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();          
1767                 try {                                                                                    
1768                     final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);         
1769                     final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);  
1770                     final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);    
1771                     final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYP🔵
1772                     final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);      
1773                     final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_🔵
1774                     final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON🔵
1775                     final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAIN🔵
1776                     final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYP🔵
1777                     final int appWidgetIdIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.APPWI🔵
1778                     final int appWidgetProviderIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites🔵
1779                     final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);  
1780                     final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);    
1781                     final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);    
1782                     final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);    
1783                     final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);    
1784                     final int restoredIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.RESTORED🔵
1785                     // final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);     
1786                     // final int displayModeIndex = c.getColumnIndexOrThrow(                             
1787                     // LauncherSettings.Favorites.DISPLAY_MODE);                                         
1788                     ShortcutInfo info;                                                                   
1789                     String intentDescription;                                                            
1790                     LauncherAppWidgetInfo appWidgetInfo;                                                 
1791                     int container;                                                                       
1792                     long id;                                                                             
1793                     Intent intent;                                                                       
1794                     while ((!mStopped) && c.moveToNext()) {                                              
1795                         AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);               
1796                         try {                                                                            
1797                             int itemType = c.getInt(itemTypeIndex);                                      
1798                             boolean restored = 0 != c.getInt(restoredIndex);                             
1799                             switch (itemType) {                                                          
1800                                 case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION :                  
1801                                 case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT :                     
1802                                     id = c.getLong(idIndex);                                             
1803                                     intentDescription = c.getString(intentIndex);                        
1804                                     try {                                                                
1805                                         intent = Intent.parseUri(intentDescription, 0);                  
1806                                         ComponentName cn = intent.getComponent();                        
1807                                         if ((cn != null) && (!isValidPackageComponent(manager, cn))) {   
1808                                             if (restored) {                                              
1809                                                 // might be installed later                              
1810                                                 Launcher.addDumpLog(TAG, "package not yet restored: " + c🔵
1811                                             } else {                                                     
1812                                                 if (!mAppsCanBeOnRemoveableStorage) {                    
1813                                                     // Log the invalid package, and remove it            
1814                                                     Launcher.addDumpLog(TAG, "Invalid package removed: " 🔵
1815                                                     itemsToRemove.add(id);                               
1816                                                 } else {                                                 
1817                                                     // If apps can be on external storage, then we just  
1818                                                     // leave them for the user to remove (maybe add      
1819                                                     // visual treatment to it)                           
1820                                                     Launcher.addDumpLog(TAG, "Invalid package found: " + 🔵
1821                                                 }                                                        
1822                                                 continue;                                                
1823                                             }                                                            
1824                                         } else if (restored) {                                           
1825                                             // no special handling necessary for this restored item      
1826                                             restoredRows.add(id);                                        
1827                                             restored = false;                                            
1828                                         }                                                                
1829                                     } catch (URISyntaxException e) {                                     
1830                                         Launcher.addDumpLog(TAG, "Invalid uri: " + intentDescription, tru🔵
1831                                         continue;                                                        
1832                                     }                                                                    
1833                                     if (restored) {                                                      
1834                                         Launcher.addDumpLog(TAG, "constructing info for partially restore🔵
1835                                         info = getRestoredItemInfo(c, titleIndex, intent);               
1836                                         intent = getRestoredItemIntent(c, context, intent);              
1837                                     } else if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATI🔵
1838                                         info = getShortcutInfo(manager, intent, context, c, iconIndex, ti🔵
1839                                     } else {                                                             
1840                                         info = getShortcutInfo(c, context, iconTypeIndex, iconPackageInde🔵
1841                                         // App shortcuts that used to be automatically added to Launcher 
1842                                         // didn't always have the correct intent flags set, so do that   
1843                                         // here                                                          
1844                                         if ((((intent.getAction() != null) && (intent.getCategories() != 🔵
1845                                             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_A🔵
1846                                         }                                                                
1847                                     }                                                                    
1848                                     if (info != null) {                                                  
1849                                         info.id = id;                                                    
1850                                         info.intent = intent;                                            
1851                                         container = c.getInt(containerIndex);                            
1852                                         info.container = container;                                      
1853                                         info.screenId = c.getInt(screenIndex);                           
1854                                         info.cellX = c.getInt(cellXIndex);                               
1855                                         info.cellY = c.getInt(cellYIndex);                               
1856                                         info.spanX = 1;                                                  
1857                                         info.spanY = 1;                                                  
1858                                         // check & update map of what's occupied                         
1859                                         deleteOnInvalidPlacement.set(false);                             
1860                                         if (!checkItemPlacement(occupied, info, deleteOnInvalidPlacement)🔵
1861                                             if (deleteOnInvalidPlacement.get()) {                        
1862                                                 itemsToRemove.add(id);                                   
1863                                             }                                                            
1864                                             break;                                                       
1865                                         }                                                                
1866                                         switch (container) {                                             
1867                                             case LauncherSettings.Favorites.CONTAINER_DESKTOP :          
1868                                             case LauncherSettings.Favorites.CONTAINER_HOTSEAT :          
1869                                                 sBgWorkspaceItems.add(info);                             
1870                                                 break;                                                   
1871                                             default :                                                    
1872                                                 // Item is in a user folder                              
1873                                                 FolderInfo folderInfo = findOrMakeFolder(sBgFolders, cont🔵
1874                                                 folderInfo.add(info);                                    
1875                                                 break;                                                   
1876                                         }                                                                
1877                                         sBgItemsIdMap.put(info.id, info);                                
1878                                         // now that we've loaded everthing re-save it with the           
1879                                         // icon in case it disappears somehow.                           
1880                                         queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);        
1881                                     } else {                                                             
1882                                         throw new RuntimeException("Unexpected null ShortcutInfo");      
1883                                     }                                                                    
1884                                     break;                                                               
1885                                 case LauncherSettings.Favorites.ITEM_TYPE_FOLDER :                       
1886                                     id = c.getLong(idIndex);                                             
1887                                     FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);            
1888                                     folderInfo.title = c.getString(titleIndex);                          
1889                                     folderInfo.id = id;                                                  
1890                                     container = c.getInt(containerIndex);                                
1891                                     folderInfo.container = container;                                    
1892                                     folderInfo.screenId = c.getInt(screenIndex);                         
1893                                     folderInfo.cellX = c.getInt(cellXIndex);                             
1894                                     folderInfo.cellY = c.getInt(cellYIndex);                             
1895                                     folderInfo.spanX = 1;                                                
1896                                     folderInfo.spanY = 1;                                                
1897                                     // check & update map of what's occupied                             
1898                                     deleteOnInvalidPlacement.set(false);                                 
1899                                     if (!checkItemPlacement(occupied, folderInfo, deleteOnInvalidPlacemen🔵
1900                                         if (deleteOnInvalidPlacement.get()) {                            
1901                                             itemsToRemove.add(id);                                       
1902                                         }                                                                
1903                                         break;                                                           
1904                                     }                                                                    
1905                                     switch (container) {                                                 
1906                                         case LauncherSettings.Favorites.CONTAINER_DESKTOP :              
1907                                         case LauncherSettings.Favorites.CONTAINER_HOTSEAT :              
1908                                             sBgWorkspaceItems.add(folderInfo);                           
1909                                             break;                                                       
1910                                     }                                                                    
1911                                     if (restored) {                                                      
1912                                         // no special handling required for restored folders             
1913                                         restoredRows.add(id);                                            
1914                                     }                                                                    
1915                                     sBgItemsIdMap.put(folderInfo.id, folderInfo);                        
1916                                     sBgFolders.put(folderInfo.id, folderInfo);                           
1917                                     break;                                                               
1918                                 case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET :                    
1919                                     // Read all Launcher-specific widget details                         
1920                                     int appWidgetId = c.getInt(appWidgetIdIndex);                        
1921                                     String savedProvider = c.getString(appWidgetProviderIndex);          
1922                                     id = c.getLong(idIndex);                                             
1923                                     final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(appWi🔵
1924                                     if ((!isSafeMode) && (((provider == null) || (provider.provider == nu🔵
1925                                         String log = (("Deleting widget that isn't installed anymore: id=🔵
1926                                         Log.e(TAG, log);                                                 
1927                                         Launcher.addDumpLog(TAG, log, false);                            
1928                                         itemsToRemove.add(id);                                           
1929                                     } else {                                                             
1930                                         appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, provider.p🔵
1931                                         appWidgetInfo.id = id;                                           
1932                                         appWidgetInfo.screenId = c.getInt(screenIndex);                  
1933                                         appWidgetInfo.cellX = c.getInt(cellXIndex);                      
1934                                         appWidgetInfo.cellY = c.getInt(cellYIndex);                      
1935                                         appWidgetInfo.spanX = c.getInt(spanXIndex);                      
1936                                         appWidgetInfo.spanY = c.getInt(spanYIndex);                      
1937                                         int[] minSpan = Launcher.getMinSpanForWidget(context, provider); 
1938                                         appWidgetInfo.minSpanX = minSpan[0];                             
1939                                         appWidgetInfo.minSpanY = minSpan[1];                             
1940                                         container = c.getInt(containerIndex);                            
1941                                         if ((container != LauncherSettings.Favorites.CONTAINER_DESKTOP) &🔵
1942                                             Log.e(TAG, "Widget found where container != " + "CONTAINER_DE🔵
1943                                             continue;                                                    
1944                                         }                                                                
1945                                         appWidgetInfo.container = c.getInt(containerIndex);              
1946                                         // check & update map of what's occupied                         
1947                                         deleteOnInvalidPlacement.set(false);                             
1948                                         if (!checkItemPlacement(occupied, appWidgetInfo, deleteOnInvalidP🔵
1949                                             if (deleteOnInvalidPlacement.get()) {                        
1950                                                 itemsToRemove.add(id);                                   
1951                                             }                                                            
1952                                             break;                                                       
1953                                         }                                                                
1954                                         String providerName = provider.provider.flattenToString();       
1955                                         if (!providerName.equals(savedProvider)) {                       
1956                                             ContentValues values = new ContentValues();                  
1957                                             values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER, pro🔵
1958                                             String where = BaseColumns._ID + "= ?";                      
1959                                             String[] args = new java.lang.String[]{ Integer.toString(c.ge🔵
1960                                             contentResolver.update(contentUri, values, where, args);     
1961                                         }                                                                
1962                                         sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);              
1963                                         sBgAppWidgets.add(appWidgetInfo);                                
1964                                     }                                                                    
1965                                     break;                                                               
1966                             }                                                                            
1967                         } catch (java.lang.Exception e) {                                                
1968                             Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);      
1969                         }                                                                                
1970                     }                                                                                    
1971                 } finally {                                                                              
1972                     if (c != null) {                                                                     
1973                         c.close();                                                                       
1974                     }                                                                                    
1975                 }                                                                                        
1976                 // Break early if we've stopped loading                                                  
1977                 if (mStopped) {                                                                          
1978                     clearSBgDataStructures();                                                            
1979                     return false;                                                                        
1980                 }                                                                                        
1981                 if (itemsToRemove.size() > 0) {                                                          
1982                     ContentProviderClient client = contentResolver.acquireContentProviderClient(LauncherS🔵
1983                     // Remove dead items                                                                 
1984                     for (long id : itemsToRemove) {                                                      
1985                         if (DEBUG_LOADERS) {                                                             
1986                             Log.d(TAG, "Removed id = " + id);                                            
1987                         }                                                                                
1988                         // Don't notify content observers                                                
1989                         try {                                                                            
1990                             client.delete(LauncherSettings.Favorites.getContentUri(id, false), null, null🔵
1991                         } catch (RemoteException e) {                                                    
1992                             Log.w(TAG, "Could not remove id = " + id);                                   
1993                         }                                                                                
1994                     }                                                                                    
1995                 }                                                                                        
1996                 if (restoredRows.size() > 0) {                                                           
1997                     ContentProviderClient updater = contentResolver.acquireContentProviderClient(Launcher🔵
1998                     // Update restored items that no longer require special handling                     
1999                     try {                                                                                
2000                         StringBuilder selectionBuilder = new StringBuilder();                            
2001                         selectionBuilder.append(LauncherSettings.Favorites._ID);                         
2002                         selectionBuilder.append(" IN (");                                                
2003                         selectionBuilder.append(TextUtils.join(", ", restoredRows));                     
2004                         selectionBuilder.append(")");                                                    
2005                         ContentValues values = new ContentValues();                                      
2006                         values.put(LauncherSettings.Favorites.RESTORED, 0);                              
2007                         updater.update(LauncherSettings.Favorites.CONTENT_URI, values, selectionBuilder.t🔵
2008                     } catch (RemoteException e) {                                                        
2009                         Log.w(TAG, "Could not update restored rows");                                    
2010                     }                                                                                    
2011                 }                                                                                        
2012                 if (loadedOldDb) {                                                                       
2013                     long maxScreenId = 0;                                                                
2014                     // If we're importing we use the old screen order.                                   
2015                     for (ItemInfo item : sBgItemsIdMap.values()) {                                       
2016                         long screenId = item.screenId;                                                   
2017                         if ((item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) && (!sBgWork🔵
2018                             sBgWorkspaceScreens.add(screenId);                                           
2019                             if (screenId > maxScreenId) {                                                
2020                                 maxScreenId = screenId;                                                  
2021                             }                                                                            
2022                         }                                                                                
2023                     }                                                                                    
2024                     Collections.sort(sBgWorkspaceScreens);                                               
2025                     // Log to disk                                                                       
2026                     Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);          
2027                     Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " + TextUtils.join(", ", 🔵
2028                     LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);               
2029                     updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                            
2030                     // Update the max item id after we load an old db                                    
2031                     long maxItemId = 0;                                                                  
2032                     // If we're importing we use the old screen order.                                   
2033                     for (ItemInfo item : sBgItemsIdMap.values()) {                                       
2034                         maxItemId = Math.max(maxItemId, item.id);                                        
2035                     }                                                                                    
2036                     LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);                   
2037                 } else {                                                                                 
2038                     TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);            
2039                     for (Integer i : orderedScreens.keySet()) {                                          
2040                         sBgWorkspaceScreens.add(orderedScreens.get(i));                                  
2041                     }                                                                                    
2042                     // Log to disk                                                                       
2043                     Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " + TextUtils.join(", ", 🔵
2044                     // Remove any empty screens                                                          
2045                     ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);            
2046                     for (ItemInfo item : sBgItemsIdMap.values()) {                                       
2047                         long screenId = item.screenId;                                                   
2048                         if ((item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) && unusedScr🔵
2049                             unusedScreens.remove(screenId);                                              
2050                         }                                                                                
2051                     }                                                                                    
2052                     // If there are any empty screens remove them, and update.                           
2053                     if (unusedScreens.size() != 0) {                                                     
2054                         // Log to disk                                                                   
2055                         Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " + TextUti🔵
2056                         sBgWorkspaceScreens.removeAll(unusedScreens);                                    
2057                         updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                        
2058                     }                                                                                    
2059                 }                                                                                        
2060                 if (DEBUG_LOADERS) {                                                                     
2061                     Log.d(TAG, ("loaded workspace in " + (SystemClock.uptimeMillis() - t)) + "ms");      
2062                     Log.d(TAG, "workspace layout: ");                                                    
2063                     int nScreens = occupied.size();                                                      
2064                     for (int y = 0; y < countY; y++) {                                                   
2065                         String line = "";                                                                
2066                         Iterator<Long> iter = occupied.keySet().iterator();                              
2067                         while (iter.hasNext()) {                                                         
2068                             long screenId = iter.next();                                                 
2069                             if (screenId > 0) {                                                          
2070                                 line += " | ";                                                           
2071                             }                                                                            
2072                             for (int x = 0; x < countX; x++) {                                           
2073                                 line += (occupied.get(screenId)[x][y] != null) ? "#" : ".";              
2074                             }                                                                            
2075                         }                                                                                
2076                         Log.d(TAG, ("[ " + line) + " ]");                                                
2077                     }                                                                                    
2078                 }                                                                                        
2079             }                                                                                            
2080             return loadedOldDb;                                                                          
2081         }                                                                                                
2082                                                                                                          
2083         /** Filters the set of items who are directly or indirectly (via another container) on the       
2084          * specified screen. */                                                                          
2085         private void filterCurrentWorkspaceItems(long currentScreenId,                                   
2086                 ArrayList<ItemInfo> allWorkspaceItems,                                                   
2087                 ArrayList<ItemInfo> currentScreenItems,                                                  
2088                 ArrayList<ItemInfo> otherScreenItems) {                                                  
2089             // Purge any null ItemInfos                                                                  
2090             Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                      
2091             while (iter.hasNext()) {                                                                     
2092                 ItemInfo i = iter.next();                                                                
2093                 if (i == null) {                                                                         
2094                     iter.remove();                                                                       
2095                 }                                                                                        
2096             }                                                                                            
2097                                                                                                          
2098             // Order the set of items by their containers first, this allows use to walk through the     
2099             // list sequentially, build up a list of containers that are in the specified screen,        
2100             // as well as all items in those containers.                                                 
2101             Set<Long> itemsOnScreen = new HashSet<Long>();                                               
2102             Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                             
2103                 @Override                                                                                
2104                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2105                     return (int) (lhs.container - rhs.container);                                        
2106                 }                                                                                        
2107             });                                                                                          
2108             for (ItemInfo info : allWorkspaceItems) {                                                    
2109                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                    
2110                     if (info.screenId == currentScreenId) {                                              
2111                         currentScreenItems.add(info);                                                    
2112                         itemsOnScreen.add(info.id);                                                      
2113                     } else {                                                                             
2114                         otherScreenItems.add(info);                                                      
2115                     }                                                                                    
2116                 } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
2117                     currentScreenItems.add(info);                                                        
2118                     itemsOnScreen.add(info.id);                                                          
2119                 } else {                                                                                 
2120                     if (itemsOnScreen.contains(info.container)) {                                        
2121                         currentScreenItems.add(info);                                                    
2122                         itemsOnScreen.add(info.id);                                                      
2123                     } else {                                                                             
2124                         otherScreenItems.add(info);                                                      
2125                     }                                                                                    
2126                 }                                                                                        
2127             }                                                                                            
2128         }                                                                                                
2129                                                                                                          
2130         /** Filters the set of widgets which are on the specified screen. */                             
2131         private void filterCurrentAppWidgets(long currentScreenId,                                       
2132                 ArrayList<LauncherAppWidgetInfo> appWidgets,                                             
2133                 ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                   
2134                 ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                   
2135                                                                                                          
2136             for (LauncherAppWidgetInfo widget : appWidgets) {                                            
2137                 if (widget == null) continue;                                                            
2138                 if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                  
2139                         widget.screenId == currentScreenId) {                                            
2140                     currentScreenWidgets.add(widget);                                                    
2141                 } else {                                                                                 
2142                     otherScreenWidgets.add(widget);                                                      
2143                 }                                                                                        
2144             }                                                                                            
2145         }                                                                                                
2146                                                                                                          
2147         /** Filters the set of folders which are on the specified screen. */                             
2148         private void filterCurrentFolders(long currentScreenId,                                          
2149                 HashMap<Long, ItemInfo> itemsIdMap,                                                      
2150                 HashMap<Long, FolderInfo> folders,                                                       
2151                 HashMap<Long, FolderInfo> currentScreenFolders,                                          
2152                 HashMap<Long, FolderInfo> otherScreenFolders) {                                          
2153                                                                                                          
2154             for (long id : folders.keySet()) {                                                           
2155                 ItemInfo info = itemsIdMap.get(id);                                                      
2156                 FolderInfo folder = folders.get(id);                                                     
2157                 if (info == null || folder == null) continue;                                            
2158                 if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                    
2159                         info.screenId == currentScreenId) {                                              
2160                     currentScreenFolders.put(id, folder);                                                
2161                 } else {                                                                                 
2162                     otherScreenFolders.put(id, folder);                                                  
2163                 }                                                                                        
2164             }                                                                                            
2165         }                                                                                                
2166                                                                                                          
2167         /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to          
2168          * right) */                                                                                     
2169         private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                   
2170             final LauncherAppState app = LauncherAppState.getInstance();                                 
2171             final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                          
2172             // XXX: review this                                                                          
2173             Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                
2174                 @Override                                                                                
2175                 public int compare(ItemInfo lhs, ItemInfo rhs) {                                         
2176                     int cellCountX = (int) grid.numColumns;                                              
2177                     int cellCountY = (int) grid.numRows;                                                 
2178                     int screenOffset = cellCountX * cellCountY;                                          
2179                     int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat      
2180                     long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +           
2181                             lhs.cellY * cellCountX + lhs.cellX);                                         
2182                     long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +           
2183                             rhs.cellY * cellCountX + rhs.cellX);                                         
2184                     return (int) (lr - rr);                                                              
2185                 }                                                                                        
2186             });                                                                                          
2187         }                                                                                                
2188                                                                                                          
2189         private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                  
2190                 final ArrayList<Long> orderedScreens) {                                                  
2191             final Runnable r = new Runnable() {                                                          
2192                 @Override                                                                                
2193                 public void run() {                                                                      
2194                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2195                     if (callbacks != null) {                                                             
2196                         callbacks.bindScreens(orderedScreens);                                           
2197                     }                                                                                    
2198                 }                                                                                        
2199             };                                                                                           
2200             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2201         }                                                                                                
2202                                                                                                          
2203         private void bindWorkspaceItems(final Callbacks oldCallbacks,                                    
2204                 final ArrayList<ItemInfo> workspaceItems,                                                
2205                 final ArrayList<LauncherAppWidgetInfo> appWidgets,                                       
2206                 final HashMap<Long, FolderInfo> folders,                                                 
2207                 ArrayList<Runnable> deferredBindRunnables) {                                             
2208                                                                                                          
2209             final boolean postOnMainThread = (deferredBindRunnables != null);                            
2210                                                                                                          
2211             // Bind the workspace items                                                                  
2212             int N = workspaceItems.size();                                                               
2213             for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                   
2214                 final int start = i;                                                                     
2215                 final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                        
2216                 final Runnable r = new Runnable() {                                                      
2217                     @Override                                                                            
2218                     public void run() {                                                                  
2219                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2220                         if (callbacks != null) {                                                         
2221                             callbacks.bindItems(workspaceItems, start, start+chunkSize,                  
2222                                     false);                                                              
2223                         }                                                                                
2224                     }                                                                                    
2225                 };                                                                                       
2226                 if (postOnMainThread) {                                                                  
2227                     deferredBindRunnables.add(r);                                                        
2228                 } else {                                                                                 
2229                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2230                 }                                                                                        
2231             }                                                                                            
2232                                                                                                          
2233             // Bind the folders                                                                          
2234             if (!folders.isEmpty()) {                                                                    
2235                 final Runnable r = new Runnable() {                                                      
2236                     public void run() {                                                                  
2237                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2238                         if (callbacks != null) {                                                         
2239                             callbacks.bindFolders(folders);                                              
2240                         }                                                                                
2241                     }                                                                                    
2242                 };                                                                                       
2243                 if (postOnMainThread) {                                                                  
2244                     deferredBindRunnables.add(r);                                                        
2245                 } else {                                                                                 
2246                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2247                 }                                                                                        
2248             }                                                                                            
2249                                                                                                          
2250             // Bind the widgets, one at a time                                                           
2251             N = appWidgets.size();                                                                       
2252             for (int i = 0; i < N; i++) {                                                                
2253                 final LauncherAppWidgetInfo widget = appWidgets.get(i);                                  
2254                 final Runnable r = new Runnable() {                                                      
2255                     public void run() {                                                                  
2256                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2257                         if (callbacks != null) {                                                         
2258                             callbacks.bindAppWidget(widget);                                             
2259                         }                                                                                
2260                     }                                                                                    
2261                 };                                                                                       
2262                 if (postOnMainThread) {                                                                  
2263                     deferredBindRunnables.add(r);                                                        
2264                 } else {                                                                                 
2265                     runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                    
2266                 }                                                                                        
2267             }                                                                                            
2268         }                                                                                                
2269                                                                                                          
2270         /**                                                                                              
2271          * Binds all loaded data to actual views on the main thread.                                     
2272          */                                                                                              
2273         private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {               
2274             final long t = SystemClock.uptimeMillis();                                                   
2275             Runnable r;                                                                                  
2276                                                                                                          
2277             // Don't use these two variables in any of the callback runnables.                           
2278             // Otherwise we hold a reference to them.                                                    
2279             final Callbacks oldCallbacks = mCallbacks.get();                                             
2280             if (oldCallbacks == null) {                                                                  
2281                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2282                 Log.w(TAG, "LoaderTask running with no launcher");                                       
2283                 return;                                                                                  
2284             }                                                                                            
2285                                                                                                          
2286             // Save a copy of all the bg-thread collections                                              
2287             ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                              
2288             ArrayList<LauncherAppWidgetInfo> appWidgets =                                                
2289                     new ArrayList<LauncherAppWidgetInfo>();                                              
2290             HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                         
2291             HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                          
2292             ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                    
2293             synchronized (sBgLock) {                                                                     
2294                 workspaceItems.addAll(sBgWorkspaceItems);                                                
2295                 appWidgets.addAll(sBgAppWidgets);                                                        
2296                 folders.putAll(sBgFolders);                                                              
2297                 itemsIdMap.putAll(sBgItemsIdMap);                                                        
2298                 orderedScreenIds.addAll(sBgWorkspaceScreens);                                            
2299             }                                                                                            
2300                                                                                                          
2301             final boolean isLoadingSynchronously =                                                       
2302                     synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                               
2303             int currScreen = isLoadingSynchronously ? synchronizeBindPage :                              
2304                 oldCallbacks.getCurrentWorkspaceScreen();                                                
2305             if (currScreen >= orderedScreenIds.size()) {                                                 
2306                 // There may be no workspace screens (just hotseat items and an empty page).             
2307                 currScreen = PagedView.INVALID_RESTORE_PAGE;                                             
2308             }                                                                                            
2309             final int currentScreen = currScreen;                                                        
2310             final long currentScreenId = currentScreen < 0                                               
2311                     ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                           
2312                                                                                                          
2313             // Load all the items that are on the current page first (and in the process, unbind         
2314             // all the existing workspace items before we call startBinding() below.                     
2315             unbindWorkspaceItemsOnMainThread();                                                          
2316                                                                                                          
2317             // Separate the items that are on the current screen, and all the other remaining items      
2318             ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                       
2319             ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                         
2320             ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                         
2321                     new ArrayList<LauncherAppWidgetInfo>();                                              
2322             ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                           
2323                     new ArrayList<LauncherAppWidgetInfo>();                                              
2324             HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                  
2325             HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                    
2326                                                                                                          
2327             filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,          
2328                     otherWorkspaceItems);                                                                
2329             filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                      
2330                     otherAppWidgets);                                                                    
2331             filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                   
2332                     otherFolders);                                                                       
2333             sortWorkspaceItemsSpatially(currentWorkspaceItems);                                          
2334             sortWorkspaceItemsSpatially(otherWorkspaceItems);                                            
2335                                                                                                          
2336             // Tell the workspace that we're about to start binding items                                
2337             r = new Runnable() {                                                                         
2338                 public void run() {                                                                      
2339                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2340                     if (callbacks != null) {                                                             
2341                         callbacks.startBinding();                                                        
2342                     }                                                                                    
2343                 }                                                                                        
2344             };                                                                                           
2345             runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                            
2346                                                                                                          
2347             bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                        
2348                                                                                                          
2349             // Load items on the current page                                                            
2350             bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                   
2351                     currentFolders, null);                                                               
2352             if (isLoadingSynchronously) {                                                                
2353                 r = new Runnable() {                                                                     
2354                     public void run() {                                                                  
2355                         Callbacks callbacks = tryGetCallbacks(oldCallbacks);                             
2356                         if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {      
2357                             callbacks.onPageBoundSynchronously(currentScreen);                           
2358                         }                                                                                
2359                     }                                                                                    
2360                 };                                                                                       
2361                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2362             }                                                                                            
2363                                                                                                          
2364             // Load all the remaining pages (if we are loading synchronously, we want to defer this      
2365             // work until after the first render)                                                        
2366             mDeferredBindRunnables.clear();                                                              
2367             bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,         
2368                     (isLoadingSynchronously ? mDeferredBindRunnables : null));                           
2369                                                                                                          
2370             // Tell the workspace that we're done binding items                                          
2371             r = new Runnable() {                                                                         
2372                 public void run() {                                                                      
2373                     Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                 
2374                     if (callbacks != null) {                                                             
2375                         callbacks.finishBindingItems(isUpgradePath);                                     
2376                     }                                                                                    
2377                                                                                                          
2378                     // If we're profiling, ensure this is the last thing in the queue.                   
2379                     if (DEBUG_LOADERS) {                                                                 
2380                         Log.d(TAG, "bound workspace in "                                                 
2381                             + (SystemClock.uptimeMillis()-t) + "ms");                                    
2382                     }                                                                                    
2383                                                                                                          
2384                     mIsLoadingAndBindingWorkspace = false;                                               
2385                 }                                                                                        
2386             };                                                                                           
2387             if (isLoadingSynchronously) {                                                                
2388                 mDeferredBindRunnables.add(r);                                                           
2389             } else {                                                                                     
2390                 runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                        
2391             }                                                                                            
2392         }                                                                                                
2393                                                                                                          
2394         private void loadAndBindAllApps() {                                                              
2395             if (DEBUG_LOADERS) {                                                                         
2396                 Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                       
2397             }                                                                                            
2398             if (!mAllAppsLoaded) {                                                                       
2399                 loadAllApps();                                                                           
2400                 synchronized (LoaderTask.this) {                                                         
2401                     if (mStopped) {                                                                      
2402                         return;                                                                          
2403                     }                                                                                    
2404                     mAllAppsLoaded = true;                                                               
2405                 }                                                                                        
2406             } else {                                                                                     
2407                 onlyBindAllApps();                                                                       
2408             }                                                                                            
2409         }                                                                                                
2410                                                                                                          
2411         private void onlyBindAllApps() {                                                                 
2412             final Callbacks oldCallbacks = mCallbacks.get();                                             
2413             if (oldCallbacks == null) {                                                                  
2414                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2415                 Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                     
2416                 return;                                                                                  
2417             }                                                                                            
2418                                                                                                          
2419             // shallow copy                                                                              
2420             @SuppressWarnings("unchecked")                                                               
2421             final ArrayList<AppInfo> list                                                                
2422                     = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                  
2423             Runnable r = new Runnable() {                                                                
2424                 public void run() {                                                                      
2425                     final long t = SystemClock.uptimeMillis();                                           
2426                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2427                     if (callbacks != null) {                                                             
2428                         callbacks.bindAllApplications(list);                                             
2429                     }                                                                                    
2430                     if (DEBUG_LOADERS) {                                                                 
2431                         Log.d(TAG, "bound all " + list.size() + " apps from cache in "                   
2432                                 + (SystemClock.uptimeMillis()-t) + "ms");                                
2433                     }                                                                                    
2434                 }                                                                                        
2435             };                                                                                           
2436             boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());           
2437             if (isRunningOnMainThread) {                                                                 
2438                 r.run();                                                                                 
2439             } else {                                                                                     
2440                 mHandler.post(r);                                                                        
2441             }                                                                                            
2442         }                                                                                                
2443                                                                                                          
2444         private void loadAllApps() {                                                                     
2445             final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2446                                                                                                          
2447             final Callbacks oldCallbacks = mCallbacks.get();                                             
2448             if (oldCallbacks == null) {                                                                  
2449                 // This launcher has exited and nobody bothered to tell us.  Just bail.                  
2450                 Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                         
2451                 return;                                                                                  
2452             }                                                                                            
2453                                                                                                          
2454             final PackageManager packageManager = mContext.getPackageManager();                          
2455             final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                              
2456             mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                            
2457                                                                                                          
2458             // Clear the list of apps                                                                    
2459             mBgAllAppsList.clear();                                                                      
2460                                                                                                          
2461             // Query for the set of apps                                                                 
2462             final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                         
2463             List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);                
2464             if (DEBUG_LOADERS) {                                                                         
2465                 Log.d(TAG, "queryIntentActivities took "                                                 
2466                         + (SystemClock.uptimeMillis()-qiaTime) + "ms");                                  
2467                 Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");                        
2468             }                                                                                            
2469             // Fail if we don't have any apps                                                            
2470             if (apps == null || apps.isEmpty()) {                                                        
2471                 return;                                                                                  
2472             }                                                                                            
2473             // Sort the applications by name                                                             
2474             final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                        
2475             Collections.sort(apps,                                                                       
2476                     new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));              
2477             if (DEBUG_LOADERS) {                                                                         
2478                 Log.d(TAG, "sort took "                                                                  
2479                         + (SystemClock.uptimeMillis()-sortTime) + "ms");                                 
2480             }                                                                                            
2481                                                                                                          
2482             // Create the ApplicationInfos                                                               
2483             for (int i = 0; i < apps.size(); i++) {                                                      
2484                 ResolveInfo app = apps.get(i);                                                           
2485                 // This builds the icon bitmaps.                                                         
2486                 mBgAllAppsList.add(new AppInfo(packageManager, app,                                      
2487                         mIconCache, mLabelCache));                                                       
2488             }                                                                                            
2489                                                                                                          
2490             // Huh? Shouldn't this be inside the Runnable below?                                         
2491             final ArrayList<AppInfo> added = mBgAllAppsList.added;                                       
2492             mBgAllAppsList.added = new ArrayList<AppInfo>();                                             
2493                                                                                                          
2494             // Post callback on main thread                                                              
2495             mHandler.post(new Runnable() {                                                               
2496                 public void run() {                                                                      
2497                     final long bindTime = SystemClock.uptimeMillis();                                    
2498                     final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                           
2499                     if (callbacks != null) {                                                             
2500                         callbacks.bindAllApplications(added);                                            
2501                         if (DEBUG_LOADERS) {                                                             
2502                             Log.d(TAG, "bound " + added.size() + " apps in "                             
2503                                 + (SystemClock.uptimeMillis() - bindTime) + "ms");                       
2504                         }                                                                                
2505                     } else {                                                                             
2506                         Log.i(TAG, "not binding apps: no Launcher activity");                            
2507                     }                                                                                    
2508                 }                                                                                        
2509             });                                                                                          
2510                                                                                                          
2511             if (DEBUG_LOADERS) {                                                                         
2512                 Log.d(TAG, "Icons processed in "                                                         
2513                         + (SystemClock.uptimeMillis() - loadTime) + "ms");                               
2514             }                                                                                            
2515         }                                                                                                
2516                                                                                                          
2517         public void dumpState() {                                                                        
2518             synchronized (sBgLock) {                                                                     
2519                 Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                          
2520                 Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                  
2521                 Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                          
2522                 Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);          
2523                 Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                   
2524             }                                                                                            
2525         }                                                                                                
2526     }                                                                                                    
2527                                                                                                          
2528     void enqueuePackageUpdated(PackageUpdatedTask task) {                                                
2529         sWorker.post(task);                                                                              
2530     }                                                                                                    
2531                                                                                                          
2532     private class PackageUpdatedTask implements Runnable {                                               
2533         int mOp;                                                                                         
2534                                                                                                          
2535         String[] mPackages;                                                                              
2536                                                                                                          
2537         public static final int OP_NONE = 0;                                                             
2538                                                                                                          
2539         public static final int OP_ADD = 1;                                                              
2540                                                                                                          
2541         public static final int OP_UPDATE = 2;                                                           
2542                                                                                                          
2543         // uninstlled                                                                                    
2544         public static final int OP_REMOVE = 3; // uninstlled                                             
2545                                                                                                          
2546         // external media unmounted                                                                      
2547         public static final int OP_UNAVAILABLE = 4; // external media unmounted                          
2548                                                                                                          
2549         public PackageUpdatedTask(int op, String[] packages) {                                           
2550             mOp = op;                                                                                    
2551             mPackages = packages;                                                                        
2552         }                                                                                                
2553                                                                                                          
2554         public void run() {                                                                              
2555             final Context context = mApp.getContext();                                                   
2556             final String[] packages = mPackages;                                                         
2557             final int N = packages.length;                                                               
2558             switch (mOp) {                                                                               
2559                 case OP_ADD :                                                                            
2560                     for (int i = 0; i < N; i++) {                                                        
2561                         if (DEBUG_LOADERS) {                                                             
2562                             Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                        
2563                         }                                                                                
2564                         mBgAllAppsList.addPackage(context, packages[i]);                                 
2565                     }                                                                                    
2566                     break;                                                                               
2567                 case OP_UPDATE :                                                                         
2568                     for (int i = 0; i < N; i++) {                                                        
2569                         if (DEBUG_LOADERS) {                                                             
2570                             Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);                     
2571                         }                                                                                
2572                         mBgAllAppsList.updatePackage(context, packages[i]);                              
2573                         WidgetPreviewLoader.removePackageFromDb(mApp.getWidgetPreviewCacheDb(), packages[🔵
2574                     }                                                                                    
2575                     break;                                                                               
2576                 case OP_REMOVE :                                                                         
2577                 case OP_UNAVAILABLE :                                                                    
2578                     for (int i = 0; i < N; i++) {                                                        
2579                         if (DEBUG_LOADERS) {                                                             
2580                             Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);                     
2581                         }                                                                                
2582                         mBgAllAppsList.removePackage(packages[i]);                                       
2583                         WidgetPreviewLoader.removePackageFromDb(mApp.getWidgetPreviewCacheDb(), packages[🔵
2584                     }                                                                                    
2585                     break;                                                                               
2586             }                                                                                            
2587             ArrayList<AppInfo> added = null;                                                             
2588             ArrayList<AppInfo> modified = null;                                                          
2589             final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                             
2590             if (mBgAllAppsList.added.size() > 0) {                                                       
2591                 added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                    
2592                 mBgAllAppsList.added.clear();                                                            
2593             }                                                                                            
2594             if (mBgAllAppsList.modified.size() > 0) {                                                    
2595                 modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                              
2596                 mBgAllAppsList.modified.clear();                                                         
2597             }                                                                                            
2598             if (mBgAllAppsList.removed.size() > 0) {                                                     
2599                 removedApps.addAll(mBgAllAppsList.removed);                                              
2600                 mBgAllAppsList.removed.clear();                                                          
2601             }                                                                                            
2602             final Callbacks callbacks = (mCallbacks != null) ? mCallbacks.get() : null;                  
2603             if (callbacks == null) {                                                                     
2604                 Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");          
2605                 return;                                                                                  
2606             }                                                                                            
2607             if (added != null) {                                                                         
2608                 // Ensure that we add all the workspace applications to the db                           
2609                 Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;                           
2610                 if (!LauncherAppState.isDisableAllApps()) {                                              
2611                     addAndBindAddedApps(context, new ArrayList<ItemInfo>(), cb, added);                  
2612                 } else {                                                                                 
2613                     final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);               
2614                     addAndBindAddedApps(context, addedInfos, cb, added);                                 
2615                 }                                                                                        
2616             }                                                                                            
2617             if (modified != null) {                                                                      
2618                 final ArrayList<AppInfo> modifiedFinal = modified;                                       
2619                 // Update the launcher db to reflect the changes                                         
2620                 for (AppInfo a : modifiedFinal) {                                                        
2621                     ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);            
2622                     for (ItemInfo i : infos) {                                                           
2623                         if (isShortcutInfoUpdateable(i)) {                                               
2624                             ShortcutInfo info = ((ShortcutInfo) (i));                                    
2625                             info.title = a.title.toString();                                             
2626                             updateItemInDatabase(context, info);                                         
2627                         }                                                                                
2628                     }                                                                                    
2629                 }                                                                                        
2630                 mHandler.post(new Runnable() {                                                           
2631                     public void run() {                                                                  
2632                         Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;                   
2633                         if ((callbacks == cb) && (cb != null)) {                                         
2634                             callbacks.bindAppsUpdated(modifiedFinal);                                    
2635                         }                                                                                
2636                     }                                                                                    
2637                 });                                                                                      
2638             }                                                                                            
2639             final ArrayList<String> removedPackageNames = new ArrayList<String>();                       
2640             if (mOp == OP_REMOVE) {                                                                      
2641                 // Mark all packages in the broadcast to be removed                                      
2642                 removedPackageNames.addAll(Arrays.asList(packages));                                     
2643             } else if (mOp == OP_UPDATE) {                                                               
2644                 // Mark disabled packages in the broadcast to be removed                                 
2645                 final PackageManager pm = context.getPackageManager();                                   
2646                 for (int i = 0; i < N; i++) {                                                            
2647                     if (isPackageDisabled(pm, packages[i])) {                                            
2648                         removedPackageNames.add(packages[i]);                                            
2649                     }                                                                                    
2650                 }                                                                                        
2651             }                                                                                            
2652             // Remove all the components associated with this package                                    
2653             for (String pn : removedPackageNames) {                                                      
2654                 ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);                               
2655                 for (ItemInfo i : infos) {                                                               
2656                     deleteItemFromDatabase(context, i);                                                  
2657                 }                                                                                        
2658             }                                                                                            
2659             // Remove all the specific components                                                        
2660             for (AppInfo a : removedApps) {                                                              
2661                 ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);                
2662                 for (ItemInfo i : infos) {                                                               
2663                     deleteItemFromDatabase(context, i);                                                  
2664                 }                                                                                        
2665             }                                                                                            
2666             if ((!removedPackageNames.isEmpty()) || (!removedApps.isEmpty())) {                          
2667                 // Remove any queued items from the install queue                                        
2668                 String spKey = LauncherAppState.getSharedPreferencesKey();                               
2669                 SharedPreferences sp = context.getSharedPreferences(spKey, Context.MODE_PRIVATE);        
2670                 InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames);                 
2671                 // Call the components-removed callback                                                  
2672                 mHandler.post(new Runnable() {                                                           
2673                     public void run() {                                                                  
2674                         Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;                   
2675                         if ((callbacks == cb) && (cb != null)) {                                         
2676                             callbacks.bindComponentsRemoved(removedPackageNames, removedApps);           
2677                         }                                                                                
2678                     }                                                                                    
2679                 });                                                                                      
2680             }                                                                                            
2681             final ArrayList<Object> widgetsAndShortcuts = getSortedWidgetsAndShortcuts(context);         
2682             mHandler.post(new Runnable() {                                                               
2683                 @Override                                                                                
2684                 public void run() {                                                                      
2685                     Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;                       
2686                     if ((callbacks == cb) && (cb != null)) {                                             
2687                         callbacks.bindPackagesUpdated(widgetsAndShortcuts);                              
2688                     }                                                                                    
2689                 }                                                                                        
2690             });                                                                                          
2691             // Write all the logs to disk                                                                
2692             mHandler.post(new Runnable() {                                                               
2693                 public void run() {                                                                      
2694                     Callbacks cb = (mCallbacks != null) ? mCallbacks.get() : null;                       
2695                     if ((callbacks == cb) && (cb != null)) {                                             
2696                         callbacks.dumpLogsToLocalData();                                                 
2697                     }                                                                                    
2698                 }                                                                                        
2699             });                                                                                          
2700         }                                                                                                
2701     }                                                                                                    
2702                                                                                                          
2703     // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                     
2704     public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                      
2705         PackageManager packageManager = context.getPackageManager();                                     
2706         final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                           
2707         widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders());       
2708         Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                              
2709         widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));            
2710         Collections.sort(widgetsAndShortcuts,                                                            
2711             new LauncherModel.WidgetAndShortcutNameComparator(packageManager));                          
2712         return widgetsAndShortcuts;                                                                      
2713     }                                                                                                    
2714                                                                                                          
2715     private static boolean isPackageDisabled(PackageManager pm, String packageName) {                    
2716         try {                                                                                            
2717             PackageInfo pi = pm.getPackageInfo(packageName, 0);                                          
2718             return !pi.applicationInfo.enabled;                                                          
2719         } catch (NameNotFoundException e) {                                                              
2720             // Fall through                                                                              
2721         }                                                                                                
2722         return false;                                                                                    
2723     }                                                                                                    
2724                                                                                                          
2725     public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) {                 
2726         if (cn == null) {                                                                                
2727             return false;                                                                                
2728         }                                                                                                
2729         if (isPackageDisabled(pm, cn.getPackageName())) {                                                
2730             return false;                                                                                
2731         }                                                                                                
2732                                                                                                          
2733         try {                                                                                            
2734             // Check the activity                                                                        
2735             PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0);                                  
2736             return (pm.getActivityInfo(cn, 0) != null);                                                  
2737         } catch (NameNotFoundException e) {                                                              
2738             return false;                                                                                
2739         }                                                                                                
2740     }                                                                                                    
2741                                                                                                          
2742     /**                                                                                                  
2743      * Make an ShortcutInfo object for a restored application or shortcut item that points               
2744      * to a package that is not yet installed on the system.                                             
2745      */                                                                                                  
2746     public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) {              
2747         final ShortcutInfo info = new ShortcutInfo();                                                    
2748         info.usingFallbackIcon = true;                                                                   
2749         info.setIcon(getFallbackIcon());                                                                 
2750         if (cursor != null) {                                                                            
2751             info.title = cursor.getString(titleIndex);                                                   
2752         } else {                                                                                         
2753             info.title = "";                                                                             
2754         }                                                                                                
2755         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
2756         info.restoredIntent = intent;                                                                    
2757         return info;                                                                                     
2758     }                                                                                                    
2759                                                                                                          
2760     /**                                                                                                  
2761      * Make an Intent object for a restored application or shortcut item that points                     
2762      * to the market page for the item.                                                                  
2763      */                                                                                                  
2764     private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                     
2765         final boolean debug = false;                                                                     
2766         ComponentName componentName = intent.getComponent();                                             
2767         Intent marketIntent = new Intent(Intent.ACTION_VIEW);                                            
2768         Uri marketUri = new Uri.Builder().scheme("market").authority("details").appendQueryParameter("id"🔵
2769         if (debug) {                                                                                     
2770             Log.d(TAG, "manufactured intent uri: " + marketUri.toString());                              
2771         }                                                                                                
2772         marketIntent.setData(marketUri);                                                                 
2773         return marketIntent;                                                                             
2774     }                                                                                                    
2775                                                                                                          
2776     /**                                                                                                  
2777      * This is called from the code that adds shortcuts from the intent receiver.  This                  
2778      * doesn't have a Cursor, but                                                                        
2779      */                                                                                                  
2780     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {        
2781         return getShortcutInfo(manager, intent, context, null, -1, -1, null);                            
2782     }                                                                                                    
2783                                                                                                          
2784     /**                                                                                                  
2785      * Make an ShortcutInfo object for a shortcut that is an application.                                
2786      *                                                                                                   
2787      * If c is not null, then it will be used to fill in missing data like the title and icon.           
2788      */                                                                                                  
2789     public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,          
2790             Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {         
2791         ComponentName componentName = intent.getComponent();                                             
2792         final ShortcutInfo info = new ShortcutInfo();                                                    
2793         if (componentName != null && !isValidPackageComponent(manager, componentName)) {                 
2794             Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName);                    
2795             return null;                                                                                 
2796         } else {                                                                                         
2797             try {                                                                                        
2798                 PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);              
2799                 info.initFlagsAndFirstInstallTime(pi);                                                   
2800             } catch (NameNotFoundException e) {                                                          
2801                 Log.d(TAG, "getPackInfo failed for package " +                                           
2802                         componentName.getPackageName());                                                 
2803             }                                                                                            
2804         }                                                                                                
2805                                                                                                          
2806         // TODO: See if the PackageManager knows about this case.  If it doesn't                         
2807         // then return null & delete this.                                                               
2808                                                                                                          
2809         // the resource -- This may implicitly give us back the fallback icon,                           
2810         // but don't worry about that.  All we're doing with usingFallbackIcon is                        
2811         // to avoid saving lots of copies of that in the database, and most apps                         
2812         // have icons anyway.                                                                            
2813                                                                                                          
2814         // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and      
2815         // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info     
2816         // via resolveActivity().                                                                        
2817         Bitmap icon = null;                                                                              
2818         ResolveInfo resolveInfo = null;                                                                  
2819         ComponentName oldComponent = intent.getComponent();                                              
2820         Intent newIntent = new Intent(intent.getAction(), null);                                         
2821         newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                 
2822         newIntent.setPackage(oldComponent.getPackageName());                                             
2823         List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);                           
2824         for (ResolveInfo i : infos) {                                                                    
2825             ComponentName cn = new ComponentName(i.activityInfo.packageName,                             
2826                     i.activityInfo.name);                                                                
2827             if (cn.equals(oldComponent)) {                                                               
2828                 resolveInfo = i;                                                                         
2829             }                                                                                            
2830         }                                                                                                
2831         if (resolveInfo == null) {                                                                       
2832             resolveInfo = manager.resolveActivity(intent, 0);                                            
2833         }                                                                                                
2834         if (resolveInfo != null) {                                                                       
2835             icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);                           
2836         }                                                                                                
2837         // the db                                                                                        
2838         if (icon == null) {                                                                              
2839             if (c != null) {                                                                             
2840                 icon = getIconFromCursor(c, iconIndex, context);                                         
2841             }                                                                                            
2842         }                                                                                                
2843         // the fallback icon                                                                             
2844         if (icon == null) {                                                                              
2845             icon = getFallbackIcon();                                                                    
2846             info.usingFallbackIcon = true;                                                               
2847         }                                                                                                
2848         info.setIcon(icon);                                                                              
2849                                                                                                          
2850         // from the resource                                                                             
2851         if (resolveInfo != null) {                                                                       
2852             ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);              
2853             if (labelCache != null && labelCache.containsKey(key)) {                                     
2854                 info.title = labelCache.get(key);                                                        
2855             } else {                                                                                     
2856                 info.title = resolveInfo.activityInfo.loadLabel(manager);                                
2857                 if (labelCache != null) {                                                                
2858                     labelCache.put(key, info.title);                                                     
2859                 }                                                                                        
2860             }                                                                                            
2861         }                                                                                                
2862         // from the db                                                                                   
2863         if (info.title == null) {                                                                        
2864             if (c != null) {                                                                             
2865                 info.title =  c.getString(titleIndex);                                                   
2866             }                                                                                            
2867         }                                                                                                
2868         // fall back to the class name of the activity                                                   
2869         if (info.title == null) {                                                                        
2870             info.title = componentName.getClassName();                                                   
2871         }                                                                                                
2872         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                
2873         return info;                                                                                     
2874     }                                                                                                    
2875                                                                                                          
2876     static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                               
2877             ItemInfoFilter f) {                                                                          
2878         HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                            
2879         for (ItemInfo i : infos) {                                                                       
2880             if (i instanceof ShortcutInfo) {                                                             
2881                 ShortcutInfo info = (ShortcutInfo) i;                                                    
2882                 ComponentName cn = info.intent.getComponent();                                           
2883                 if (cn != null && f.filterItem(null, info, cn)) {                                        
2884                     filtered.add(info);                                                                  
2885                 }                                                                                        
2886             } else if (i instanceof FolderInfo) {                                                        
2887                 FolderInfo info = (FolderInfo) i;                                                        
2888                 for (ShortcutInfo s : info.contents) {                                                   
2889                     ComponentName cn = s.intent.getComponent();                                          
2890                     if (cn != null && f.filterItem(info, s, cn)) {                                       
2891                         filtered.add(s);                                                                 
2892                     }                                                                                    
2893                 }                                                                                        
2894             } else if (i instanceof LauncherAppWidgetInfo) {                                             
2895                 LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                  
2896                 ComponentName cn = info.providerName;                                                    
2897                 if (cn != null && f.filterItem(null, info, cn)) {                                        
2898                     filtered.add(info);                                                                  
2899                 }                                                                                        
2900             }                                                                                            
2901         }                                                                                                
2902         return new ArrayList<ItemInfo>(filtered);                                                        
2903     }                                                                                                    
2904                                                                                                          
2905     private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {                             
2906         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
2907             @Override                                                                                    
2908             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
2909                 return cn.getPackageName().equals(pn);                                                   
2910             }                                                                                            
2911         };                                                                                               
2912         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
2913     }                                                                                                    
2914                                                                                                          
2915     private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {                 
2916         ItemInfoFilter filter  = new ItemInfoFilter() {                                                  
2917             @Override                                                                                    
2918             public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                
2919                 return cn.equals(cname);                                                                 
2920             }                                                                                            
2921         };                                                                                               
2922         return filterItemInfos(sBgItemsIdMap.values(), filter);                                          
2923     }                                                                                                    
2924                                                                                                          
2925     public static boolean isShortcutInfoUpdateable(ItemInfo i) {                                         
2926         if (i instanceof ShortcutInfo) {                                                                 
2927             ShortcutInfo info = ((ShortcutInfo) (i));                                                    
2928             // We need to check for ACTION_MAIN otherwise getComponent() might                           
2929             // return null for some shortcuts (for instance, for shortcuts to                            
2930             // web pages.)                                                                               
2931             Intent intent = info.intent;                                                                 
2932             ComponentName name = intent.getComponent();                                                  
2933             if (((info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) && Intent.ACTION_MAI🔵
2934                 return true;                                                                             
2935             }                                                                                            
2936             // placeholder shortcuts get special treatment, let them through too.                        
2937             if (info.getRestoredIntent() != null) {                                                      
2938                 return true;                                                                             
2939             }                                                                                            
2940         }                                                                                                
2941         return false;                                                                                    
2942     }                                                                                                    
2943                                                                                                          
2944     /**                                                                                                  
2945      * Make an ShortcutInfo object for a shortcut that isn't an application.                             
2946      */                                                                                                  
2947     private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                      
2948             int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,               
2949             int titleIndex) {                                                                            
2950                                                                                                          
2951         Bitmap icon = null;                                                                              
2952         final ShortcutInfo info = new ShortcutInfo();                                                    
2953         info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                   
2954                                                                                                          
2955         // TODO: If there's an explicit component and we can't install that, delete it.                  
2956                                                                                                          
2957         info.title = c.getString(titleIndex);                                                            
2958                                                                                                          
2959         int iconType = c.getInt(iconTypeIndex);                                                          
2960         switch (iconType) {                                                                              
2961         case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                              
2962             String packageName = c.getString(iconPackageIndex);                                          
2963             String resourceName = c.getString(iconResourceIndex);                                        
2964             PackageManager packageManager = context.getPackageManager();                                 
2965             info.customIcon = false;                                                                     
2966             // the resource                                                                              
2967             try {                                                                                        
2968                 Resources resources = packageManager.getResourcesForApplication(packageName);            
2969                 if (resources != null) {                                                                 
2970                     final int id = resources.getIdentifier(resourceName, null, null);                    
2971                     icon = Utilities.createIconBitmap(                                                   
2972                             mIconCache.getFullResIcon(resources, id), context);                          
2973                 }                                                                                        
2974             } catch (Exception e) {                                                                      
2975                 // drop this.  we have other places to look for icons                                    
2976             }                                                                                            
2977             // the db                                                                                    
2978             if (icon == null) {                                                                          
2979                 icon = getIconFromCursor(c, iconIndex, context);                                         
2980             }                                                                                            
2981             // the fallback icon                                                                         
2982             if (icon == null) {                                                                          
2983                 icon = getFallbackIcon();                                                                
2984                 info.usingFallbackIcon = true;                                                           
2985             }                                                                                            
2986             break;                                                                                       
2987         case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                
2988             icon = getIconFromCursor(c, iconIndex, context);                                             
2989             if (icon == null) {                                                                          
2990                 icon = getFallbackIcon();                                                                
2991                 info.customIcon = false;                                                                 
2992                 info.usingFallbackIcon = true;                                                           
2993             } else {                                                                                     
2994                 info.customIcon = true;                                                                  
2995             }                                                                                            
2996             break;                                                                                       
2997         default:                                                                                         
2998             icon = getFallbackIcon();                                                                    
2999             info.usingFallbackIcon = true;                                                               
3000             info.customIcon = false;                                                                     
3001             break;                                                                                       
3002         }                                                                                                
3003         info.setIcon(icon);                                                                              
3004         return info;                                                                                     
3005     }                                                                                                    
3006                                                                                                          
3007     Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                 
3008         @SuppressWarnings("all") // suppress dead code warning                                           
3009         final boolean debug = false;                                                                     
3010         if (debug) {                                                                                     
3011             Log.d(TAG, "getIconFromCursor app="                                                          
3012                     + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));           
3013         }                                                                                                
3014         byte[] data = c.getBlob(iconIndex);                                                              
3015         try {                                                                                            
3016             return Utilities.createIconBitmap(                                                           
3017                     BitmapFactory.decodeByteArray(data, 0, data.length), context);                       
3018         } catch (Exception e) {                                                                          
3019             return null;                                                                                 
3020         }                                                                                                
3021     }                                                                                                    
3022                                                                                                          
3023     ShortcutInfo addShortcut(Context context, Intent data, long container, int screen,                   
3024             int cellX, int cellY, boolean notify) {                                                      
3025         final ShortcutInfo info = infoFromShortcutIntent(context, data, null);                           
3026         if (info == null) {                                                                              
3027             return null;                                                                                 
3028         }                                                                                                
3029         addItemToDatabase(context, info, container, screen, cellX, cellY, notify);                       
3030                                                                                                          
3031         return info;                                                                                     
3032     }                                                                                                    
3033                                                                                                          
3034     /**                                                                                                  
3035      * Attempts to find an AppWidgetProviderInfo that matches the given component.                       
3036      */                                                                                                  
3037     AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,                        
3038             ComponentName component) {                                                                   
3039         List<AppWidgetProviderInfo> widgets =                                                            
3040             AppWidgetManager.getInstance(context).getInstalledProviders();                               
3041         for (AppWidgetProviderInfo info : widgets) {                                                     
3042             if (info.provider.equals(component)) {                                                       
3043                 return info;                                                                             
3044             }                                                                                            
3045         }                                                                                                
3046         return null;                                                                                     
3047     }                                                                                                    
3048                                                                                                          
3049     /**                                                                                                  
3050      * Returns a list of all the widgets that can handle configuration with a particular mimeType.       
3051      */                                                                                                  
3052     List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {        
3053         final PackageManager packageManager = context.getPackageManager();                               
3054         final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =                         
3055             new ArrayList<WidgetMimeTypeHandlerData>();                                                  
3056                                                                                                          
3057         final Intent supportsIntent =                                                                    
3058             new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);                         
3059         supportsIntent.setType(mimeType);                                                                
3060                                                                                                          
3061         // Create a set of widget configuration components that we can test against                      
3062         final List<AppWidgetProviderInfo> widgets =                                                      
3063             AppWidgetManager.getInstance(context).getInstalledProviders();                               
3064         final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =             
3065             new HashMap<ComponentName, AppWidgetProviderInfo>();                                         
3066         for (AppWidgetProviderInfo info : widgets) {                                                     
3067             configurationComponentToWidget.put(info.configure, info);                                    
3068         }                                                                                                
3069                                                                                                          
3070         // Run through each of the intents that can handle this type of clip data, and cross             
3071         // reference them with the components that are actual configuration components                   
3072         final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,        
3073                 PackageManager.MATCH_DEFAULT_ONLY);                                                      
3074         for (ResolveInfo info : activities) {                                                            
3075             final ActivityInfo activityInfo = info.activityInfo;                                         
3076             final ComponentName infoComponent = new ComponentName(activityInfo.packageName,              
3077                     activityInfo.name);                                                                  
3078             if (configurationComponentToWidget.containsKey(infoComponent)) {                             
3079                 supportedConfigurationActivities.add(                                                    
3080                         new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,                        
3081                                 configurationComponentToWidget.get(infoComponent)));                     
3082             }                                                                                            
3083         }                                                                                                
3084         return supportedConfigurationActivities;                                                         
3085     }                                                                                                    
3086                                                                                                          
3087     ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {             
3088         Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                           
3089         String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                   
3090         Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                         
3091                                                                                                          
3092         if (intent == null) {                                                                            
3093             // If the intent is null, we can't construct a valid ShortcutInfo, so we return null         
3094             Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                  
3095             return null;                                                                                 
3096         }                                                                                                
3097                                                                                                          
3098         Bitmap icon = null;                                                                              
3099         boolean customIcon = false;                                                                      
3100         ShortcutIconResource iconResource = null;                                                        
3101                                                                                                          
3102         if (bitmap != null && bitmap instanceof Bitmap) {                                                
3103             icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);          
3104             customIcon = true;                                                                           
3105         } else {                                                                                         
3106             Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);             
3107             if (extra != null && extra instanceof ShortcutIconResource) {                                
3108                 try {                                                                                    
3109                     iconResource = (ShortcutIconResource) extra;                                         
3110                     final PackageManager packageManager = context.getPackageManager();                   
3111                     Resources resources = packageManager.getResourcesForApplication(                     
3112                             iconResource.packageName);                                                   
3113                     final int id = resources.getIdentifier(iconResource.resourceName, null, null);       
3114                     icon = Utilities.createIconBitmap(                                                   
3115                             mIconCache.getFullResIcon(resources, id), context);                          
3116                 } catch (Exception e) {                                                                  
3117                     Log.w(TAG, "Could not load shortcut icon: " + extra);                                
3118                 }                                                                                        
3119             }                                                                                            
3120         }                                                                                                
3121                                                                                                          
3122         final ShortcutInfo info = new ShortcutInfo();                                                    
3123                                                                                                          
3124         if (icon == null) {                                                                              
3125             if (fallbackIcon != null) {                                                                  
3126                 icon = fallbackIcon;                                                                     
3127             } else {                                                                                     
3128                 icon = getFallbackIcon();                                                                
3129                 info.usingFallbackIcon = true;                                                           
3130             }                                                                                            
3131         }                                                                                                
3132         info.setIcon(icon);                                                                              
3133                                                                                                          
3134         info.title = name;                                                                               
3135         info.intent = intent;                                                                            
3136         info.customIcon = customIcon;                                                                    
3137         info.iconResource = iconResource;                                                                
3138                                                                                                          
3139         return info;                                                                                     
3140     }                                                                                                    
3141                                                                                                          
3142     boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,             
3143             int iconIndex) {                                                                             
3144         // If apps can't be on SD, don't even bother.                                                    
3145         if (!mAppsCanBeOnRemoveableStorage) {                                                            
3146             return false;                                                                                
3147         }                                                                                                
3148         // If this icon doesn't have a custom icon, check to see                                         
3149         // what's stored in the DB, and if it doesn't match what                                         
3150         // we're going to show, store what we are going to show back                                     
3151         // into the DB.  We do this so when we're loading, if the                                        
3152         // package manager can't find an icon (for example because                                       
3153         // the app is on SD) then we can use that instead.                                               
3154         if (!info.customIcon && !info.usingFallbackIcon) {                                               
3155             cache.put(info, c.getBlob(iconIndex));                                                       
3156             return true;                                                                                 
3157         }                                                                                                
3158         return false;                                                                                    
3159     }                                                                                                    
3160                                                                                                          
3161     void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                              
3162         boolean needSave = false;                                                                        
3163         try {                                                                                            
3164             if (data != null) {                                                                          
3165                 Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                      
3166                 Bitmap loaded = info.getIcon(mIconCache);                                                
3167                 needSave = !saved.sameAs(loaded);                                                        
3168             } else {                                                                                     
3169                 needSave = true;                                                                         
3170             }                                                                                            
3171         } catch (Exception e) {                                                                          
3172             needSave = true;                                                                             
3173         }                                                                                                
3174         if (needSave) {                                                                                  
3175             Log.d(TAG, "going to save icon bitmap for info=" + info);                                    
3176             // This is slower than is ideal, but this only happens once                                  
3177             // or when the app is updated with a new icon.                                               
3178             updateItemInDatabase(context, info);                                                         
3179         }                                                                                                
3180     }                                                                                                    
3181                                                                                                          
3182     /**                                                                                                  
3183      * Return an existing FolderInfo object if we have encountered this ID previously,                   
3184      * or make a new one.                                                                                
3185      */                                                                                                  
3186     private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {             
3187         // See if a placeholder was created for us already                                               
3188         FolderInfo folderInfo = folders.get(id);                                                         
3189         if (folderInfo == null) {                                                                        
3190             // No placeholder -- create a new instance                                                   
3191             folderInfo = new FolderInfo();                                                               
3192             folders.put(id, folderInfo);                                                                 
3193         }                                                                                                
3194         return folderInfo;                                                                               
3195     }                                                                                                    
3196                                                                                                          
3197     public static final Comparator<AppInfo> getAppNameComparator() {                                     
3198         final Collator collator = Collator.getInstance();                                                
3199         return new Comparator<AppInfo>() {                                                               
3200             public final int compare(AppInfo a, AppInfo b) {                                             
3201                 int result = collator.compare(a.title.toString().trim(),                                 
3202                         b.title.toString().trim());                                                      
3203                 if (result == 0) {                                                                       
3204                     result = a.componentName.compareTo(b.componentName);                                 
3205                 }                                                                                        
3206                 return result;                                                                           
3207             }                                                                                            
3208         };                                                                                               
3209     }                                                                                                    
3210                                                                                                          
3211     public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR = new Comparator<AppInfo>() {    
3212         public final int compare(AppInfo a, AppInfo b) {                                                 
3213             if (a.firstInstallTime < b.firstInstallTime) {                                               
3214                 return 1;                                                                                
3215             }                                                                                            
3216             if (a.firstInstallTime > b.firstInstallTime) {                                               
3217                 return -1;                                                                               
3218             }                                                                                            
3219             return 0;                                                                                    
3220         }                                                                                                
3221     };                                                                                                   
3222                                                                                                          
3223     public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() {                    
3224         final Collator collator = Collator.getInstance();                                                
3225         return new Comparator<AppWidgetProviderInfo>() {                                                 
3226             public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {                 
3227                 return collator.compare(a.label.toString().trim(), b.label.toString().trim());           
3228             }                                                                                            
3229         };                                                                                               
3230     }                                                                                                    
3231                                                                                                          
3232     static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                             
3233         if (info.activityInfo != null) {                                                                 
3234             return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);             
3235         } else {                                                                                         
3236             return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);               
3237         }                                                                                                
3238     }                                                                                                    
3239                                                                                                          
3240     public static class ShortcutNameComparator implements Comparator<ResolveInfo> {                      
3241         private Collator mCollator;                                                                      
3242                                                                                                          
3243         private PackageManager mPackageManager;                                                          
3244                                                                                                          
3245         private HashMap<Object, CharSequence> mLabelCache;                                               
3246                                                                                                          
3247         ShortcutNameComparator(PackageManager pm) {                                                      
3248             mPackageManager = pm;                                                                        
3249             mLabelCache = new HashMap<Object, CharSequence>();                                           
3250             mCollator = Collator.getInstance();                                                          
3251         }                                                                                                
3252                                                                                                          
3253         ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {            
3254             mPackageManager = pm;                                                                        
3255             mLabelCache = labelCache;                                                                    
3256             mCollator = Collator.getInstance();                                                          
3257         }                                                                                                
3258                                                                                                          
3259         public final int compare(ResolveInfo a, ResolveInfo b) {                                         
3260             CharSequence labelA;                                                                         
3261             CharSequence labelB;                                                                         
3262             ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);                       
3263             ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);                       
3264             if (mLabelCache.containsKey(keyA)) {                                                         
3265                 labelA = mLabelCache.get(keyA);                                                          
3266             } else {                                                                                     
3267                 labelA = a.loadLabel(mPackageManager).toString().trim();                                 
3268                 mLabelCache.put(keyA, labelA);                                                           
3269             }                                                                                            
3270             if (mLabelCache.containsKey(keyB)) {                                                         
3271                 labelB = mLabelCache.get(keyB);                                                          
3272             } else {                                                                                     
3273                 labelB = b.loadLabel(mPackageManager).toString().trim();                                 
3274                 mLabelCache.put(keyB, labelB);                                                           
3275             }                                                                                            
3276             return mCollator.compare(labelA, labelB);                                                    
3277         }                                                                                                
3278     }                                                                                                    
3279                                                                                                          
3280     public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                  
3281         private Collator mCollator;                                                                      
3282                                                                                                          
3283         private PackageManager mPackageManager;                                                          
3284                                                                                                          
3285         private HashMap<Object, String> mLabelCache;                                                     
3286                                                                                                          
3287         WidgetAndShortcutNameComparator(PackageManager pm) {                                             
3288             mPackageManager = pm;                                                                        
3289             mLabelCache = new HashMap<Object, String>();                                                 
3290             mCollator = Collator.getInstance();                                                          
3291         }                                                                                                
3292                                                                                                          
3293         public final int compare(Object a, Object b) {                                                   
3294             String labelA;                                                                               
3295             String labelB;                                                                               
3296             if (mLabelCache.containsKey(a)) {                                                            
3297                 labelA = mLabelCache.get(a);                                                             
3298             } else {                                                                                     
3299                 labelA = (a instanceof AppWidgetProviderInfo) ? ((AppWidgetProviderInfo) (a)).label : ((R🔵
3300                 mLabelCache.put(a, labelA);                                                              
3301             }                                                                                            
3302             if (mLabelCache.containsKey(b)) {                                                            
3303                 labelB = mLabelCache.get(b);                                                             
3304             } else {                                                                                     
3305                 labelB = (b instanceof AppWidgetProviderInfo) ? ((AppWidgetProviderInfo) (b)).label : ((R🔵
3306                 mLabelCache.put(b, labelB);                                                              
3307             }                                                                                            
3308             return mCollator.compare(labelA, labelB);                                                    
3309         }                                                                                                
3310     }                                                                                                    
3311                                                                                                          
3312     public void dumpState() {                                                                            
3313         Log.d(TAG, "mCallbacks=" + mCallbacks);                                                          
3314         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                  
3315         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                
3316         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);            
3317         AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);          
3318         if (mLoaderTask != null) {                                                                       
3319             mLoaderTask.dumpState();                                                                     
3320         } else {                                                                                         
3321             Log.d(TAG, "mLoaderTask=null");                                                              
3322         }                                                                                                
3323     }                                                                                                    
3324 }                                                                                                        




















































































































































































































































































































































































ours vs. base theirs vs. base
   1  /*                                                                                                                
   2   * Copyright (C) 2008 The Android Open Source Project                                                             
   3   *                                                                                                                
   4   * Licensed under the Apache License, Version 2.0 (the "License");                                                
   5   * you may not use this file except in compliance with the License.                                               
   6   * You may obtain a copy of the License at                                                                        
   7   *                                                                                                                
   8   *      http://www.apache.org/licenses/LICENSE-2.0                                                                
   9   *                                                                                                                
  10   * Unless required by applicable law or agreed to in writing, software                                            
  11   * distributed under the License is distributed on an "AS IS" BASIS,                                              
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                       
  13   * See the License for the specific language governing permissions and                                            
  14   * limitations under the License.                                                                                 
  15   */                                                                                                               
  16                                                                                                                    
  17  package com.android.launcher3;                                                                                    
  18                                                                                                                    
  19  import android.app.SearchManager;                                                                                 
  20  import android.appwidget.AppWidgetManager;                                                                        
  21  import android.appwidget.AppWidgetProviderInfo;                                                                   
  22  import android.content.*;                                                                                         
  23  import android.content.Intent.ShortcutIconResource;                                                               
  24  import android.content.pm.ActivityInfo;                                                                           
  25  import android.content.pm.PackageInfo;                                                                            
  26  import android.content.pm.PackageManager;                                                                         
  27  import android.content.pm.PackageManager.NameNotFoundException;                                                   
  28  import android.content.pm.ResolveInfo;                                                                            
  29  import android.content.res.Configuration;                                                                         
  30  import android.content.res.Resources;                                                                             
  31  import android.database.Cursor;                                                                                   
  32  import android.graphics.Bitmap;                                                                                   
  33  import android.graphics.BitmapFactory;                                                                            
  34  import android.net.Uri;                                                                                           
  35  import android.os.Environment;                                                                                    
  36  import android.os.Handler;                                                                                        
  37  import android.os.HandlerThread;                                                                                  
  38  import android.os.Parcelable;                                                                                     
  39  import android.os.Process;                                                                                        
  40  import android.os.RemoteException;                                                                                
  41  import android.os.SystemClock;                                                                                    
  42  import android.provider.BaseColumns;                                                                              
  43  import android.text.TextUtils;                                                                                    
  44  import android.util.Log;                                                                                          
  45  import android.util.Pair;                                                                                         
  46                                                                                                                    
  47  import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;                                     
  48                                                                                                                    
  49  import java.lang.ref.WeakReference;                                                                               
  50  import java.net.URISyntaxException;                                                                               
  51  import java.text.Collator;                                                                                        
  52  import java.util.ArrayList;                                                                                       
  53  import java.util.Arrays;                                                                                          
  54  import java.util.Collection;                                                                                      
  55  import java.util.Collections;                                                                                     
  56  import java.util.Comparator;                                                                                      
  57  import java.util.HashMap;                                                                                         
  58  import java.util.HashSet;                                                                                         
  59  import java.util.Iterator;                                                                                        
  60  import java.util.List;                                                                                            
  61  import java.util.Set;                                                                                             
  62  import java.util.TreeMap;                                                                                         
  63  import java.util.concurrent.atomic.AtomicBoolean;                                                                 
  64                                                                                                                    
  65  /**                                                                                                               
  66   * Maintains in-memory state of the Launcher. It is expected that there should be only one                        
  67   * LauncherModel object held in a static. Also provide APIs for updating the database state                       
  68   * for the Launcher.                                                                                              
  69   */                                                                                                               
  70  public class LauncherModel extends BroadcastReceiver {                                                            
  71      static final boolean DEBUG_LOADERS = false;                                                                   
  72      static final String TAG = "Launcher.Model";                                                                   
  73                                                                                                                    
  74      // true = use a "More Apps" folder for non-workspace apps on upgrade                                          
  75      // false = strew non-workspace apps across the workspace on upgrade                                           
  76      public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;                                             
  77                                                                                                                    
  78      public static final int LOADER_FLAG_NONE = 0;                                                                 
  79      public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                                 
  80      public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                               
  81                                                                                                                    
  82      private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                               
  83      private static final long INVALID_SCREEN_ID = -1L;                                                            
  84                                                                                                                    
  85      private final boolean mAppsCanBeOnRemoveableStorage;                                                          
  86      private final boolean mOldContentProviderExists;                                                              
  87                                                                                                                    
  88      private final LauncherAppState mApp;                                                                          
  89      private final Object mLock = new Object();                                                                    
  90      private DeferredHandler mHandler = new DeferredHandler();                                                     
  91      private LoaderTask mLoaderTask;                                                                               
  92      private boolean mIsLoaderTaskRunning;                                                                         
  93      private volatile boolean mFlushingWorkerThread;                                                               
  94                                                                                                                    
  95      // Specific runnable types that are run on the main thread deferred handler, this allows us to                
  96      // clear all queued binding runnables when the Launcher activity is destroyed.                                
  97      private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                                     
  98      private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                                    
  99                                                                                                                    
 100                                                                                                                    
 101      private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                      
 102      static {                                                                                                      
 103          sWorkerThread.start();                                                                                    
 104      }                                                                                                             
 105      private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                                
 106                                                                                                                    
 107      // We start off with everything not loaded.  After that, we assume that                                       
 108      // our monitoring of the package manager provides all updates and we never                                    
 109      // need to do a requery.  These are only ever touched from the loader thread.                                 
 110      private boolean mWorkspaceLoaded;                                                                             
 111      private boolean mAllAppsLoaded;                                                                               
 112                                                                                                                    
 113      // When we are loading pages synchronously, we can't just post the binding of items on the side               
 114      // pages as this delays the rotation process.  Instead, we wait for a callback from the first                 
 115      // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start                
 116      // a normal load, we also clear this set of Runnables.                                                        
 117      static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                          
 118                                                                                                                    
 119      private WeakReference<Callbacks> mCallbacks;                                                                  
 120                                                                                                                    
 121      // < only access in worker thread >                                                                           
 122      AllAppsList mBgAllAppsList;                                                                                   
 123                                                                                                                    
 124      // The lock that must be acquired before referencing any static bg data structures.  Unlike                   
 125      // other locks, this one can generally be held long-term because we never expect any of these                 
 126      // static data structures to be referenced outside of the worker thread except on the first                   
 127      // load after configuration change.                                                                           
 128      static final Object sBgLock = new Object();                                                                   
 129                                                                                                                    
 130      // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by                        
 131      // LauncherModel to their ids                                                                                 
 132      static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                           
 133                                                                                                                    
 134      // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts                
 135      //       created by LauncherModel that are directly on the home screen (however, no widgets or                
 136      //       shortcuts within folders).                                                                           
 137      static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                               
 138                                                                                                                    
 139      // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()             
 140      static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                                 
 141          new ArrayList<LauncherAppWidgetInfo>();                                                                   
 142                                                                                                                    
 143      // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                            
 144      static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                          
 145                                                                                                                    
 146      // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database               
 147      static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                          
 148                                                                                                                    
 149      // sBgWorkspaceScreens is the ordered set of workspace screens.                                               
 150      static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                                     
 151                                                                                                                    
 152      // </ only access in worker thread >                                                                          
 153                                                                                                                    
 154      private IconCache mIconCache;                                                                                 
 155      private Bitmap mDefaultIcon;                                                                                  
 156                                                                                                                    
 157      protected int mPreviousConfigMcc;                                                                             
 158                                                                                                                    
 159      public interface Callbacks {                                                                                  
 160          public boolean setLoadOnResume();                                                                         
 161          public int getCurrentWorkspaceScreen();                                                                   
 162          public void startBinding();                                                                               
 163          public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                                  
 164                                boolean forceAnimateIcons);                                                         
 165          public void bindScreens(ArrayList<Long> orderedScreenIds);                                                
 166          public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                             
 167          public void bindFolders(HashMap<Long,FolderInfo> folders);                                                
 168          public void finishBindingItems(boolean upgradePath);                                                      
 169          public void bindAppWidget(LauncherAppWidgetInfo info);                                                    
 170          public void bindAllApplications(ArrayList<AppInfo> apps);                                                 
 171          public void bindAppsAdded(ArrayList<Long> newScreens,                                                     
 172                                    ArrayList<ItemInfo> addNotAnimated,                                             
 173                                    ArrayList<ItemInfo> addAnimated,                                                
 174                                    ArrayList<AppInfo> addedApps);                                                  
 175          public void bindAppsUpdated(ArrayList<AppInfo> apps);                                                     
 176          public void bindComponentsRemoved(ArrayList<String> packageNames,                                         
 177                          ArrayList<AppInfo> appInfos);                                                             
 178          public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                                   
 179          public void bindSearchablesChanged();                                                                     
 180          public boolean isAllAppsButtonRank(int rank);                                                             
 181          public void onPageBoundSynchronously(int page);                                                           
 182          public void dumpLogsToLocalData();                                                                        
 183      }                                                                                                             
 184                                                                                                                    
 185      public interface ItemInfoFilter {                                                                             
 186          public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                              
 187      }                                                                                                             
 188                                                                                                                    
 189      LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                               
 190          Context context = app.getContext();                                                                       
 191          ContentResolver contentResolver = context.getContentResolver();                                           
 192                                                                                                                    
 193          mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                                 
 194          mOldContentProviderExists = (contentResolver.acquireContentProviderClient(                                
 195                  LauncherSettings.Favorites.OLD_CONTENT_URI) != null);                                             
 196          mApp = app;                                                                                               
 197          mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                                   
 198          mIconCache = iconCache;                                                                                   
 199                                                                                                                    
 200          final Resources res = context.getResources();                                                             
 201          Configuration config = res.getConfiguration();                                                            
 202          mPreviousConfigMcc = config.mcc;                                                                          
 203      }                                                                                                             
 204                                                                                                                    
 205      /** Runs the specified runnable immediately if called from the main thread, otherwise it is                   
 206       * posted on the main thread handler. */                                                                      
 207      private void runOnMainThread(Runnable r) {                                                                    
 208          runOnMainThread(r, 0);                                                                                    
 209      }                                                                                                             
 210      private void runOnMainThread(Runnable r, int type) {                                                          
 211          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 212              // If we are on the worker thread, post onto the main handler                                         
 213              mHandler.post(r);                                                                                     
 214          } else {                                                                                                  
 215              r.run();                                                                                              
 216          }                                                                                                         
 217      }                                                                                                             
 218                                                                                                                    
 219      /** Runs the specified runnable immediately if called from the worker thread, otherwise it is                 
 220       * posted on the worker thread handler. */                                                                    
 221      private static void runOnWorkerThread(Runnable r) {                                                           
 222          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 223              r.run();                                                                                              
 224          } else {                                                                                                  
 225              // If we are not on the worker thread, then post to the worker handler                                
 226              sWorker.post(r);                                                                                      
 227          }                                                                                                         
 228      }                                                                                                             
 229                                                                                                                    
 230      boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                                      
 231          return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                                  
 232      }                                                                                                             
 233                                                                                                                    
 234      static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy,                        
 235                                   long screen) {                                                                   
 236          LauncherAppState app = LauncherAppState.getInstance();                                                    
 237          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 238          final int xCount = (int) grid.numColumns;                                                                 
 239          final int yCount = (int) grid.numRows;                                                                    
 240          boolean[][] occupied = new boolean[xCount][yCount];                                                       
 241                                                                                                                    
 242          int cellX, cellY, spanX, spanY;                                                                           
 243          for (int i = 0; i < items.size(); ++i) {                                                                  
 244              final ItemInfo item = items.get(i);                                                                   
 245              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                                 
 246                  if (item.screenId == screen) {                                                                    
 247                      cellX = item.cellX;                                                                           
 248                      cellY = item.cellY;                                                                           
 249                      spanX = item.spanX;                                                                           
 250                      spanY = item.spanY;                                                                           
 251                      for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {                         
 252                          for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {                     
 253                              occupied[x][y] = true;                                                                
 254                          }                                                                                         
 255                      }                                                                                             
 256                  }                                                                                                 
 257              }                                                                                                     
 258          }                                                                                                         
 259                                                                                                                    
 260          return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);                                     
 261      }                                                                                                             
 262      static Pair<Long, int[]> findNextAvailableIconSpace(Context context, String name,                             
 263                                                          Intent launchIntent,                                      
 264                                                          int firstScreenIndex,                                     
 265                                                          ArrayList<Long> workspaceScreens) {                       
 266          // Lock on the app so that we don't try and get the items while apps are being added                      
 267          LauncherAppState app = LauncherAppState.getInstance();                                                    
 268          LauncherModel model = app.getModel();                                                                     
 269          boolean found = false;                                                                                    
 270          synchronized (app) {                                                                                      
 271              if (sWorkerThread.getThreadId() != Process.myTid()) {                                                 
 272                  // Flush the LauncherModel worker thread, so that if we just did another                          
 273                  // processInstallShortcut, we give it time for its shortcut to get added to the                   
 274                  // database (getItemsInLocalCoordinates reads the database)                                       
 275                  model.flushWorkerThread();                                                                        
 276              }                                                                                                     
 277              final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);                  
 278                                                                                                                    
 279              // Try adding to the workspace screens incrementally, starting at the default or center               
 280              // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))                
 281              firstScreenIndex = Math.min(firstScreenIndex, workspaceScreens.size());                               
 282              int count = workspaceScreens.size();                                                                  
 283              for (int screen = firstScreenIndex; screen < count && !found; screen++) {                             
 284                  int[] tmpCoordinates = new int[2];                                                                
 285                  if (findNextAvailableIconSpaceInScreen(items, tmpCoordinates,                                     
 286                          workspaceScreens.get(screen))) {                                                          
 287                      // Update the Launcher db                                                                     
 288                      return new Pair<Long, int[]>(workspaceScreens.get(screen), tmpCoordinates);                   
 289                  }                                                                                                 
 290              }                                                                                                     
 291          }                                                                                                         
 292          return null;                                                                                              
 293      }                                                                                                             
 294                                                                                                                    
 295 -    public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                       
 296 -        final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                                 
 297 -                                                                                                                  
 298 -        if (allAppsApps == null) {                                                                                
 299 -            throw new RuntimeException("allAppsApps must not be null");                                           
 300 -        }                                                                                                         
 301 -        if (allAppsApps.isEmpty()) {                                                                              
 302 -            return;                                                                                               
 303 -        }                                                                                                         
 304 -                                                                                                                  









 305 -        // Process the newly added applications and add them to the database first                                
 306 -        Runnable r = new Runnable() {                                                                             
 307 -            public void run() {                                                                                   
 308 -                runOnMainThread(new Runnable() {                                                                  
 309 -                    public void run() {                                                                           
 310 -                        Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                              
 311 -                        if (callbacks == cb && cb != null) {                                                      
 312 -                            callbacks.bindAppsAdded(null, null, null, allAppsApps);                               



 313 -                        }                                                                                         
 314 -                    }                                                                                             
 315 -                });                                                                                               
 316 -            }                                                                                                     
 317 -        };                                                                                                        
 318 -        runOnWorkerThread(r);                                                                                     
 319 -    }                                                                                                             
 320 -                                                                                                                  
 321 -    public void addAndBindAddedWorkspaceApps(final Context context,                                               
 322 -            final ArrayList<ItemInfo> workspaceApps) {                                                            
 323 -        final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                                 
 324 -                                                                                                                  
 325 -        if (workspaceApps == null) {                                                                              
 326 +    public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps,               
 327 +                                    final ArrayList<AppInfo> allAppsApps) {                                       
 328 +        Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                              
 329 +        addAndBindAddedApps(context, workspaceApps, cb, allAppsApps);                                             
 330 +    }                                                                                                             
 331 +    public void addAndBindAddedApps(final Context context, final ArrayList<ItemInfo> workspaceApps,               
 332 +                                final Callbacks callbacks, final ArrayList<AppInfo> allAppsApps) {                
 333 +        if (workspaceApps == null || allAppsApps == null) {                                                       
 334              throw new RuntimeException("workspaceApps and allAppsApps must not be null");                         
 335          }                                                                                                         
 336 -        if (workspaceApps.isEmpty()) {                                                                            
 337 +        if (workspaceApps.isEmpty() && allAppsApps.isEmpty()) {                                                   
 338              return;                                                                                               
 339          }                                                                                                         
 340          // Process the newly added applications and add them to the database first                                
 341          Runnable r = new Runnable() {                                                                             
 342              public void run() {                                                                                   
 343                  final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();                        
 344                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         

 345                                                                                                                    
 346                  // Get the list of workspace screens.  We need to append to this list and                         
 347                  // can not use sBgWorkspaceScreens because loadWorkspace() may not have been                      
 348                  // called.                                                                                        
 349                  ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                         
 350                  TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                          
 351                  for (Integer i : orderedScreens.keySet()) {                                                       
 352                      long screenId = orderedScreens.get(i);                                                        
 353                      workspaceScreens.add(screenId);                                                               
 354                  }                                                                                                 
 355                                                                                                                    
 356                  synchronized(sBgLock) {                                                                           
 357                      Iterator<ItemInfo> iter = workspaceApps.iterator();                                           
 358                      while (iter.hasNext()) {                                                                      
 359                          ItemInfo a = iter.next();                                                                 
 360                          final String name = a.title.toString();                                                   
 361                          final Intent launchIntent = a.getIntent();                                                
 362                                                                                                                    
 363                          // Short-circuit this logic if the icon exists somewhere on the workspace                 
 364                          if (LauncherModel.shortcutExists(context, name, launchIntent)) {                          





 365                              continue;                                                                             
 366                          }                                                                                         
 367                                                                                                                    
 368                          // Add this icon to the db, creating a new page if necessary.  If there                   
 369                          // is only the empty page then we just add items to the first page.                       
 370                          // Otherwise, we add them to the next pages.                                              
 371                          int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;                            
 372                          Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,              
 373                                  name, launchIntent, startSearchPageIndex, workspaceScreens);                      
 374                          if (coords == null) {                                                                     
 375                              LauncherProvider lp = LauncherAppState.getLauncherProvider();                         
 376                                                                                                                    
 377                              // If we can't find a valid position, then just add a new screen.                     
 378                              // This takes time so we need to re-queue the add until the new                       
 379                              // page is added.  Create as many screens as necessary to satisfy                     
 380                              // the startSearchPageIndex.                                                          
 381                              int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -                            
 382                                      workspaceScreens.size());                                                     
 383                              while (numPagesToAdd > 0) {                                                           
 384                                  long screenId = lp.generateNewScreenId();                                         
 385                                  // Save the screen id for binding in the workspace                                
 386                                  workspaceScreens.add(screenId);                                                   
 387                                  addedWorkspaceScreensFinal.add(screenId);                                         
 388                                  numPagesToAdd--;                                                                  
 389                              }                                                                                     
 390                                                                                                                    
 391                              // Find the coordinate again                                                          
 392                              coords = LauncherModel.findNextAvailableIconSpace(context,                            
 393                                      name, launchIntent, startSearchPageIndex, workspaceScreens);                  
 394                          }                                                                                         
 395                          if (coords == null) {                                                                     
 396                              throw new RuntimeException("Coordinates should not be null");                         
 397                          }                                                                                         
 398                                                                                                                    
 399                          ShortcutInfo shortcutInfo;                                                                
 400                          if (a instanceof ShortcutInfo) {                                                          
 401                              shortcutInfo = (ShortcutInfo) a;                                                      
 402                          } else if (a instanceof AppInfo) {                                                        
 403                              shortcutInfo = ((AppInfo) a).makeShortcut();                                          
 404                          } else {                                                                                  
 405                              throw new RuntimeException("Unexpected info type");                                   
 406                          }                                                                                         
 407                                                                                                                    
 408                          // Add the shortcut to the db                                                             
 409                          addItemToDatabase(context, shortcutInfo,                                                  
 410                                  LauncherSettings.Favorites.CONTAINER_DESKTOP,                                     
 411                                  coords.first, coords.second[0], coords.second[1], false);                         
 412                          // Save the ShortcutInfo for binding in the workspace                                     
 413                          addedShortcutsFinal.add(shortcutInfo);                                                    
 414                      }                                                                                             
 415                  }                                                                                                 
 416                                                                                                                    
 417                  // Update the workspace screens                                                                   
 418                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 419                                                                                                                    
 420 -                if (!addedShortcutsFinal.isEmpty()) {                                                             
 421 +                if (!addedShortcutsFinal.isEmpty() || !allAppsApps.isEmpty()) {                                   
 422                      runOnMainThread(new Runnable() {                                                              
 423                          public void run() {                                                                       
 424                              Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                          
 425                              if (callbacks == cb && cb != null) {                                                  
 426                                  final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();                
 427                                  final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();             
 428                                  if (!addedShortcutsFinal.isEmpty()) {                                             
 429                                      ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);      
 430                                      long lastScreenId = info.screenId;                                            
 431                                      for (ItemInfo i : addedShortcutsFinal) {                                      
 432                                          if (i.screenId == lastScreenId) {                                         
 433                                              addAnimated.add(i);                                                   
 434                                          } else {                                                                  
 435                                              addNotAnimated.add(i);                                                
 436                                          }                                                                         
 437                                      }                                                                             
 438                                  }                                                                                 
 439                                  callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                               
 440 -                                        addNotAnimated, addAnimated, null);                                       
 441 +                                        addNotAnimated, addAnimated, allAppsApps);                                


 442                              }                                                                                     
 443                          }                                                                                         
 444                      });                                                                                           
 445                  }                                                                                                 
 446              }                                                                                                     
 447          };                                                                                                        
 448          runOnWorkerThread(r);                                                                                     
 449      }                                                                                                             
 450                                                                                                                    
 451      public Bitmap getFallbackIcon() {                                                                             
 452          if (mDefaultIcon == null) {                                                                               
 453              final Context context = LauncherAppState.getInstance().getContext();                                  
 454              mDefaultIcon = Utilities.createIconBitmap(                                                            
 455                      mIconCache.getFullResDefaultActivityIcon(), context);                                         
 456          }                                                                                                         
 457          return Bitmap.createBitmap(mDefaultIcon);                                                                 
 458      }                                                                                                             
 459                                                                                                                    
 460      public void unbindItemInfosAndClearQueuedBindRunnables() {                                                    
 461          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 462              throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +              
 463                      "main thread");                                                                               
 464          }                                                                                                         
 465                                                                                                                    
 466          // Clear any deferred bind runnables                                                                      
 467          mDeferredBindRunnables.clear();                                                                           
 468          // Remove any queued bind runnables                                                                       
 469          mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                          
 470          // Unbind all the workspace items                                                                         
 471          unbindWorkspaceItemsOnMainThread();                                                                       
 472      }                                                                                                             
 473                                                                                                                    
 474      /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                                 
 475      void unbindWorkspaceItemsOnMainThread() {                                                                     
 476          // Ensure that we don't use the same workspace items data structure on the main thread                    
 477          // by making a copy of workspace items first.                                                             
 478          final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                                  
 479          final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                                      
 480          synchronized (sBgLock) {                                                                                  
 481              tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                          
 482              tmpAppWidgets.addAll(sBgAppWidgets);                                                                  
 483          }                                                                                                         
 484          Runnable r = new Runnable() {                                                                             
 485                  @Override                                                                                         
 486                  public void run() {                                                                               
 487                     for (ItemInfo item : tmpWorkspaceItems) {                                                      
 488                         item.unbind();                                                                             
 489                     }                                                                                              
 490                     for (ItemInfo item : tmpAppWidgets) {                                                          
 491                         item.unbind();                                                                             
 492                     }                                                                                              
 493                  }                                                                                                 
 494              };                                                                                                    
 495          runOnMainThread(r);                                                                                       
 496      }                                                                                                             
 497                                                                                                                    
 498      /**                                                                                                           
 499       * Adds an item to the DB if it was not created previously, or move it to a new                               
 500       * <container, screen, cellX, cellY>                                                                          
 501       */                                                                                                           
 502      static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                           
 503              long screenId, int cellX, int cellY) {                                                                
 504          if (item.container == ItemInfo.NO_ID) {                                                                   
 505              // From all apps                                                                                      
 506              addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                           
 507          } else {                                                                                                  
 508              // From somewhere else                                                                                
 509              moveItemInDatabase(context, item, container, screenId, cellX, cellY);                                 
 510          }                                                                                                         
 511      }                                                                                                             
 512                                                                                                                    
 513      static void checkItemInfoLocked(                                                                              
 514              final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                             
 515          ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                           
 516          if (modelItem != null && item != modelItem) {                                                             
 517              // check all the data is consistent                                                                   
 518              if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                              
 519                  ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                            
 520                  ShortcutInfo shortcut = (ShortcutInfo) item;                                                      
 521                  if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                           
 522                          modelShortcut.intent.filterEquals(shortcut.intent) &&                                     
 523                          modelShortcut.id == shortcut.id &&                                                        
 524                          modelShortcut.itemType == shortcut.itemType &&                                            
 525                          modelShortcut.container == shortcut.container &&                                          
 526                          modelShortcut.screenId == shortcut.screenId &&                                            
 527                          modelShortcut.cellX == shortcut.cellX &&                                                  
 528                          modelShortcut.cellY == shortcut.cellY &&                                                  
 529                          modelShortcut.spanX == shortcut.spanX &&                                                  
 530                          modelShortcut.spanY == shortcut.spanY &&                                                  
 531                          ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                           
 532                          (modelShortcut.dropPos != null &&                                                         
 533                                  shortcut.dropPos != null &&                                                       
 534                                  modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                                
 535                          modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                                      
 536                      // For all intents and purposes, this is the same object                                      
 537                      return;                                                                                       
 538                  }                                                                                                 
 539              }                                                                                                     
 540                                                                                                                    
 541              // the modelItem needs to match up perfectly with item if our model is                                
 542              // to be consistent with the database-- for now, just require                                         
 543              // modelItem == item or the equality check above                                                      
 544              String msg = "item: " + ((item != null) ? item.toString() : "null") +                                 
 545                      "modelItem: " +                                                                               
 546                      ((modelItem != null) ? modelItem.toString() : "null") +                                       
 547                      "Error: ItemInfo passed to checkItemInfo doesn't match original";                             
 548              RuntimeException e = new RuntimeException(msg);                                                       
 549              if (stackTrace != null) {                                                                             
 550                  e.setStackTrace(stackTrace);                                                                      
 551              }                                                                                                     
 552              throw e;                                                                                              
 553          }                                                                                                         
 554      }                                                                                                             
 555                                                                                                                    
 556      static void checkItemInfo(final ItemInfo item) {                                                              
 557          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 558          final long itemId = item.id;                                                                              
 559          Runnable r = new Runnable() {                                                                             
 560              public void run() {                                                                                   
 561                  synchronized (sBgLock) {                                                                          
 562                      checkItemInfoLocked(itemId, item, stackTrace);                                                
 563                  }                                                                                                 
 564              }                                                                                                     
 565          };                                                                                                        
 566          runOnWorkerThread(r);                                                                                     
 567      }                                                                                                             
 568                                                                                                                    
 569      static void updateItemInDatabaseHelper(Context context, final ContentValues values,                           
 570              final ItemInfo item, final String callingFunction) {                                                  
 571          final long itemId = item.id;                                                                              
 572          final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                                  
 573          final ContentResolver cr = context.getContentResolver();                                                  
 574                                                                                                                    
 575          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 576          Runnable r = new Runnable() {                                                                             
 577              public void run() {                                                                                   
 578                  cr.update(uri, values, null, null);                                                               
 579                  updateItemArrays(item, itemId, stackTrace);                                                       
 580              }                                                                                                     
 581          };                                                                                                        
 582          runOnWorkerThread(r);                                                                                     
 583      }                                                                                                             
 584                                                                                                                    
 585      static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,           
 586              final ArrayList<ItemInfo> items, final String callingFunction) {                                      
 587          final ContentResolver cr = context.getContentResolver();                                                  
 588                                                                                                                    
 589          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 590          Runnable r = new Runnable() {                                                                             
 591              public void run() {                                                                                   
 592                  ArrayList<ContentProviderOperation> ops =                                                         
 593                          new ArrayList<ContentProviderOperation>();                                                
 594                  int count = items.size();                                                                         
 595                  for (int i = 0; i < count; i++) {                                                                 
 596                      ItemInfo item = items.get(i);                                                                 
 597                      final long itemId = item.id;                                                                  
 598                      final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                      
 599                      ContentValues values = valuesList.get(i);                                                     
 600                                                                                                                    
 601                      ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());                  
 602                      updateItemArrays(item, itemId, stackTrace);                                                   
 603                                                                                                                    
 604                  }                                                                                                 
 605                  try {                                                                                             
 606                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
 607                  } catch (Exception e) {                                                                           
 608                      e.printStackTrace();                                                                          
 609                  }                                                                                                 
 610              }                                                                                                     
 611          };                                                                                                        
 612          runOnWorkerThread(r);                                                                                     
 613      }                                                                                                             
 614                                                                                                                    
 615      static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {                    
 616          // Lock on mBgLock *after* the db operation                                                               
 617          synchronized (sBgLock) {                                                                                  
 618              checkItemInfoLocked(itemId, item, stackTrace);                                                        
 619                                                                                                                    
 620              if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
 621                      item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 622                  // Item is in a folder, make sure this folder exists                                              
 623                  if (!sBgFolders.containsKey(item.container)) {                                                    
 624                      // An items container is being set to a that of an item which is not in                       
 625                      // the list of Folders.                                                                       
 626                      String msg = "item: " + item + " container being set to: " +                                  
 627                              item.container + ", not in the list of folders";                                      
 628                      Log.e(TAG, msg);                                                                              
 629                  }                                                                                                 
 630              }                                                                                                     
 631                                                                                                                    
 632              // Items are added/removed from the corresponding FolderInfo elsewhere, such                          
 633              // as in Workspace.onDrop. Here, we just add/remove them from the list of items                       
 634              // that are on the desktop, as appropriate                                                            
 635              ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                       
 636              if (modelItem != null &&                                                                              
 637                      (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                       
 638                       modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {                      
 639                  switch (modelItem.itemType) {                                                                     
 640                      case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                        
 641                      case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                           
 642                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 643                          if (!sBgWorkspaceItems.contains(modelItem)) {                                             
 644                              sBgWorkspaceItems.add(modelItem);                                                     
 645                          }                                                                                         
 646                          break;                                                                                    
 647                      default:                                                                                      
 648                          break;                                                                                    
 649                  }                                                                                                 
 650              } else {                                                                                              
 651                  sBgWorkspaceItems.remove(modelItem);                                                              
 652              }                                                                                                     
 653          }                                                                                                         
 654      }                                                                                                             
 655                                                                                                                    
 656      public void flushWorkerThread() {                                                                             
 657          mFlushingWorkerThread = true;                                                                             
 658          Runnable waiter = new Runnable() {                                                                        
 659                  public void run() {                                                                               
 660                      synchronized (this) {                                                                         
 661                          notifyAll();                                                                              
 662                          mFlushingWorkerThread = false;                                                            
 663                      }                                                                                             
 664                  }                                                                                                 
 665              };                                                                                                    
 666                                                                                                                    
 667          synchronized(waiter) {                                                                                    
 668              runOnWorkerThread(waiter);                                                                            
 669              if (mLoaderTask != null) {                                                                            
 670                  synchronized(mLoaderTask) {                                                                       
 671                      mLoaderTask.notify();                                                                         
 672                  }                                                                                                 
 673              }                                                                                                     
 674              boolean success = false;                                                                              
 675              while (!success) {                                                                                    
 676                  try {                                                                                             
 677                      waiter.wait();                                                                                
 678                      success = true;                                                                               
 679                  } catch (InterruptedException e) {                                                                
 680                  }                                                                                                 
 681              }                                                                                                     
 682          }                                                                                                         
 683      }                                                                                                             
 684                                                                                                                    
 685      /**                                                                                                           
 686       * Move an item in the DB to a new <container, screen, cellX, cellY>                                          
 687       */                                                                                                           
 688      static void moveItemInDatabase(Context context, final ItemInfo item, final long container,                    
 689              final long screenId, final int cellX, final int cellY) {                                              
 690          item.container = container;                                                                               
 691          item.cellX = cellX;                                                                                       
 692          item.cellY = cellY;                                                                                       
 693                                                                                                                    
 694          // We store hotseat items in canonical form which is this orientation invariant position                  
 695          // in the hotseat                                                                                         
 696          if (context instanceof Launcher && screenId < 0 &&                                                        
 697                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 698              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 699          } else {                                                                                                  
 700              item.screenId = screenId;                                                                             
 701          }                                                                                                         
 702                                                                                                                    
 703          final ContentValues values = new ContentValues();                                                         
 704          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 705          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 706          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 707          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 708                                                                                                                    
 709          updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                                  
 710      }                                                                                                             
 711                                                                                                                    
 712      /**                                                                                                           
 713       * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the                        
 714       * cellX, cellY have already been updated on the ItemInfos.                                                   
 715       */                                                                                                           
 716      static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                             
 717              final long container, final int screen) {                                                             
 718                                                                                                                    
 719          ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                                  
 720          int count = items.size();                                                                                 
 721                                                                                                                    
 722          for (int i = 0; i < count; i++) {                                                                         
 723              ItemInfo item = items.get(i);                                                                         
 724              item.container = container;                                                                           
 725                                                                                                                    
 726              // We store hotseat items in canonical form which is this orientation invariant position              
 727              // in the hotseat                                                                                     
 728              if (context instanceof Launcher && screen < 0 &&                                                      
 729                      container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                  
 730                  item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,                   
 731                          item.cellY);                                                                              
 732              } else {                                                                                              
 733                  item.screenId = screen;                                                                           
 734              }                                                                                                     
 735                                                                                                                    
 736              final ContentValues values = new ContentValues();                                                     
 737              values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                     
 738              values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                             
 739              values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                             
 740              values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                         
 741                                                                                                                    
 742              contentValues.add(values);                                                                            
 743          }                                                                                                         
 744          updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                         
 745      }                                                                                                             
 746                                                                                                                    
 747      /**                                                                                                           
 748       * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>                 
 749       */                                                                                                           
 750      static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,                  
 751              final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {            
 752          item.container = container;                                                                               
 753          item.cellX = cellX;                                                                                       
 754          item.cellY = cellY;                                                                                       
 755          item.spanX = spanX;                                                                                       
 756          item.spanY = spanY;                                                                                       
 757                                                                                                                    
 758          // We store hotseat items in canonical form which is this orientation invariant position                  
 759          // in the hotseat                                                                                         
 760          if (context instanceof Launcher && screenId < 0 &&                                                        
 761                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 762              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 763          } else {                                                                                                  
 764              item.screenId = screenId;                                                                             
 765          }                                                                                                         
 766                                                                                                                    
 767          final ContentValues values = new ContentValues();                                                         
 768          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 769          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 770          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 771          values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                                 
 772          values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                                 
 773          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 774                                                                                                                    
 775          updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                                
 776      }                                                                                                             
 777                                                                                                                    
 778      /**                                                                                                           
 779       * Update an item to the database in a specified container.                                                   
 780       */                                                                                                           
 781      static void updateItemInDatabase(Context context, final ItemInfo item) {                                      
 782          final ContentValues values = new ContentValues();                                                         
 783          item.onAddToDatabase(values);                                                                             
 784          item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                         
 785          updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                                
 786      }                                                                                                             
 787                                                                                                                    
 788      /**                                                                                                           
 789       * Returns true if the shortcuts already exists in the database.                                              
 790       * we identify a shortcut by its title and intent.                                                            
 791       */                                                                                                           
 792      static boolean shortcutExists(Context context, String title, Intent intent) {                                 
 793          final ContentResolver cr = context.getContentResolver();                                                  
 794          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 795              new String[] { "title", "intent" }, "title=? and intent=?",                                           
 796              new String[] { title, intent.toUri(0) }, null);                                                       
 797          boolean result = false;                                                                                   
 798          try {                                                                                                     
 799              result = c.moveToFirst();                                                                             
 800          } finally {                                                                                               
 801              c.close();                                                                                            
 802          }                                                                                                         
























 803          return result;                                                                                            
 804      }                                                                                                             
 805                                                                                                                    
 806      /**                                                                                                           
 807       * Returns an ItemInfo array containing all the items in the LauncherModel.                                   
 808       * The ItemInfo.id is not set through this function.                                                          
 809       */                                                                                                           
 810      static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {                                      
 811          ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                                    
 812          final ContentResolver cr = context.getContentResolver();                                                  
 813          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {                                
 814                  LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,                       
 815                  LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CE🔵
 816                  LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);          
 817                                                                                                                    
 818          final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);                  
 819          final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);                 
 820          final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);                       
 821          final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                         
 822          final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                         
 823          final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                         
 824          final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                         
 825                                                                                                                    
 826          try {                                                                                                     
 827              while (c.moveToNext()) {                                                                              
 828                  ItemInfo item = new ItemInfo();                                                                   
 829                  item.cellX = c.getInt(cellXIndex);                                                                
 830                  item.cellY = c.getInt(cellYIndex);                                                                
 831                  item.spanX = Math.max(1, c.getInt(spanXIndex));                                                   
 832                  item.spanY = Math.max(1, c.getInt(spanYIndex));                                                   
 833                  item.container = c.getInt(containerIndex);                                                        
 834                  item.itemType = c.getInt(itemTypeIndex);                                                          
 835                  item.screenId = c.getInt(screenIndex);                                                            
 836                                                                                                                    
 837                  items.add(item);                                                                                  
 838              }                                                                                                     
 839          } catch (Exception e) {                                                                                   
 840              items.clear();                                                                                        
 841          } finally {                                                                                               
 842              c.close();                                                                                            
 843          }                                                                                                         
 844                                                                                                                    
 845          return items;                                                                                             
 846      }                                                                                                             
 847                                                                                                                    
 848      /**                                                                                                           
 849       * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.                
 850       */                                                                                                           
 851      FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {                     
 852          final ContentResolver cr = context.getContentResolver();                                                  
 853          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                         
 854                  "_id=? and (itemType=? or itemType=?)",                                                           
 855                  new String[] { String.valueOf(id),                                                                
 856                          String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);                      
 857                                                                                                                    
 858          try {                                                                                                     
 859              if (c.moveToFirst()) {                                                                                
 860                  final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);          
 861                  final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);                 
 862                  final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);         
 863                  final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);               
 864                  final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                 
 865                  final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                 
 866                                                                                                                    
 867                  FolderInfo folderInfo = null;                                                                     
 868                  switch (c.getInt(itemTypeIndex)) {                                                                
 869                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 870                          folderInfo = findOrMakeFolder(folderList, id);                                            
 871                          break;                                                                                    
 872                  }                                                                                                 
 873                                                                                                                    
 874                  folderInfo.title = c.getString(titleIndex);                                                       
 875                  folderInfo.id = id;                                                                               
 876                  folderInfo.container = c.getInt(containerIndex);                                                  
 877                  folderInfo.screenId = c.getInt(screenIndex);                                                      
 878                  folderInfo.cellX = c.getInt(cellXIndex);                                                          
 879                  folderInfo.cellY = c.getInt(cellYIndex);                                                          
 880                                                                                                                    
 881                  return folderInfo;                                                                                
 882              }                                                                                                     
 883          } finally {                                                                                               
 884              c.close();                                                                                            
 885          }                                                                                                         
 886                                                                                                                    
 887          return null;                                                                                              
 888      }                                                                                                             
 889                                                                                                                    
 890      /**                                                                                                           
 891       * Add an item to the database in a specified container. Sets the container, screen, cellX and                
 892       * cellY fields of the item. Also assigns an ID to the item.                                                  
 893       */                                                                                                           
 894      static void addItemToDatabase(Context context, final ItemInfo item, final long container,                     
 895              final long screenId, final int cellX, final int cellY, final boolean notify) {                        
 896          item.container = container;                                                                               
 897          item.cellX = cellX;                                                                                       
 898          item.cellY = cellY;                                                                                       
 899          // We store hotseat items in canonical form which is this orientation invariant position                  
 900          // in the hotseat                                                                                         
 901          if (context instanceof Launcher && screenId < 0 &&                                                        
 902                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 903              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 904          } else {                                                                                                  
 905              item.screenId = screenId;                                                                             
 906          }                                                                                                         
 907                                                                                                                    
 908          final ContentValues values = new ContentValues();                                                         
 909          final ContentResolver cr = context.getContentResolver();                                                  
 910          item.onAddToDatabase(values);                                                                             
 911                                                                                                                    
 912          item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                                     
 913          values.put(LauncherSettings.Favorites._ID, item.id);                                                      
 914          item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                         
 915                                                                                                                    
 916          Runnable r = new Runnable() {                                                                             
 917              public void run() {                                                                                   
 918                  cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                                       
 919                          LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                          
 920                                                                                                                    
 921                  // Lock on mBgLock *after* the db operation                                                       
 922                  synchronized (sBgLock) {                                                                          
 923                      checkItemInfoLocked(item.id, item, null);                                                     
 924                      sBgItemsIdMap.put(item.id, item);                                                             
 925                      switch (item.itemType) {                                                                      
 926                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
 927                              sBgFolders.put(item.id, (FolderInfo) item);                                           
 928                              // Fall through                                                                       
 929                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
 930                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
 931                              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                 
 932                                      item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
 933                                  sBgWorkspaceItems.add(item);                                                      
 934                              } else {                                                                              
 935                                  if (!sBgFolders.containsKey(item.container)) {                                    
 936                                      // Adding an item to a folder that doesn't exist.                             
 937                                      String msg = "adding item: " + item + " to a folder that " +                  
 938                                              " doesn't exist";                                                     
 939                                      Log.e(TAG, msg);                                                              
 940                                  }                                                                                 
 941                              }                                                                                     
 942                              break;                                                                                
 943                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
 944                              sBgAppWidgets.add((LauncherAppWidgetInfo) item);                                      
 945                              break;                                                                                
 946                      }                                                                                             
 947                  }                                                                                                 
 948              }                                                                                                     
 949          };                                                                                                        
 950          runOnWorkerThread(r);                                                                                     
 951      }                                                                                                             
 952                                                                                                                    
 953      /**                                                                                                           
 954       * Creates a new unique child id, for a given cell span across all layouts.                                   
 955       */                                                                                                           
 956      static int getCellLayoutChildId(                                                                              
 957              long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {                  
 958          return (((int) container & 0xFF) << 24)                                                                   
 959                  | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);                   
 960      }                                                                                                             
 961                                                                                                                    
 962      /**                                                                                                           
 963       * Removes the specified item from the database                                                               
 964       * @param context                                                                                             
 965       * @param item                                                                                                
 966       */                                                                                                           
 967      static void deleteItemFromDatabase(Context context, final ItemInfo item) {                                    
 968          final ContentResolver cr = context.getContentResolver();                                                  
 969          final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);                         
 970                                                                                                                    
 971          Runnable r = new Runnable() {                                                                             
 972              public void run() {                                                                                   
 973                  cr.delete(uriToDelete, null, null);                                                               
 974                                                                                                                    
 975                  // Lock on mBgLock *after* the db operation                                                       
 976                  synchronized (sBgLock) {                                                                          
 977                      switch (item.itemType) {                                                                      
 978                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
 979                              sBgFolders.remove(item.id);                                                           
 980                              for (ItemInfo info: sBgItemsIdMap.values()) {                                         
 981                                  if (info.container == item.id) {                                                  
 982                                      // We are deleting a folder which still contains items that                   
 983                                      // think they are contained by that folder.                                   
 984                                      String msg = "deleting a folder (" + item + ") which still " +                
 985                                              "contains items (" + info + ")";                                      
 986                                      Log.e(TAG, msg);                                                              
 987                                  }                                                                                 
 988                              }                                                                                     
 989                              sBgWorkspaceItems.remove(item);                                                       
 990                              break;                                                                                
 991                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
 992                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
 993                              sBgWorkspaceItems.remove(item);                                                       
 994                              break;                                                                                
 995                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
 996                              sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                                   
 997                              break;                                                                                
 998                      }                                                                                             
 999                      sBgItemsIdMap.remove(item.id);                                                                
1000                      sBgDbIconCache.remove(item);                                                                  
1001                  }                                                                                                 
1002              }                                                                                                     
1003          };                                                                                                        
1004          runOnWorkerThread(r);                                                                                     
1005      }                                                                                                             
1006                                                                                                                    
1007      /**                                                                                                           
1008       * Update the order of the workspace screens in the database. The array list contains                         
1009       * a list of screen ids in the order that they should appear.                                                 
1010       */                                                                                                           
1011      void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                             
1012          // Log to disk                                                                                            
1013          Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                                
1014          Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);                 
1015                                                                                                                    
1016          final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                         
1017          final ContentResolver cr = context.getContentResolver();                                                  
1018          final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                            
1019                                                                                                                    
1020          // Remove any negative screen ids -- these aren't persisted                                               
1021          Iterator<Long> iter = screensCopy.iterator();                                                             
1022          while (iter.hasNext()) {                                                                                  
1023              long id = iter.next();                                                                                
1024              if (id < 0) {                                                                                         
1025                  iter.remove();                                                                                    
1026              }                                                                                                     
1027          }                                                                                                         
1028                                                                                                                    
1029          Runnable r = new Runnable() {                                                                             
1030              @Override                                                                                             
1031              public void run() {                                                                                   
1032                  // Clear the table                                                                                
1033                  cr.delete(uri, null, null);                                                                       
1034                  int count = screensCopy.size();                                                                   
1035                  ContentValues[] values = new ContentValues[count];                                                
1036                  for (int i = 0; i < count; i++) {                                                                 
1037                      ContentValues v = new ContentValues();                                                        
1038                      long screenId = screensCopy.get(i);                                                           
1039                      v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                                       
1040                      v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                                      
1041                      values[i] = v;                                                                                
1042                  }                                                                                                 
1043                  cr.bulkInsert(uri, values);                                                                       
1044                                                                                                                    
1045                  synchronized (sBgLock) {                                                                          
1046                      sBgWorkspaceScreens.clear();                                                                  
1047                      sBgWorkspaceScreens.addAll(screensCopy);                                                      
1048                  }                                                                                                 
1049              }                                                                                                     
1050          };                                                                                                        
1051          runOnWorkerThread(r);                                                                                     
1052      }                                                                                                             
1053                                                                                                                    
1054      /**                                                                                                           
1055       * Remove the contents of the specified folder from the database                                              
1056       */                                                                                                           
1057      static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {                        
1058          final ContentResolver cr = context.getContentResolver();                                                  
1059                                                                                                                    
1060          Runnable r = new Runnable() {                                                                             
1061              public void run() {                                                                                   
1062                  cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);                  
1063                  // Lock on mBgLock *after* the db operation                                                       
1064                  synchronized (sBgLock) {                                                                          
1065                      sBgItemsIdMap.remove(info.id);                                                                
1066                      sBgFolders.remove(info.id);                                                                   
1067                      sBgDbIconCache.remove(info);                                                                  
1068                      sBgWorkspaceItems.remove(info);                                                               
1069                  }                                                                                                 
1070                                                                                                                    
1071                  cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                 
1072                          LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                              
1073                  // Lock on mBgLock *after* the db operation                                                       
1074                  synchronized (sBgLock) {                                                                          
1075                      for (ItemInfo childInfo : info.contents) {                                                    
1076                          sBgItemsIdMap.remove(childInfo.id);                                                       
1077                          sBgDbIconCache.remove(childInfo);                                                         
1078                      }                                                                                             
1079                  }                                                                                                 
1080              }                                                                                                     
1081          };                                                                                                        
1082          runOnWorkerThread(r);                                                                                     
1083      }                                                                                                             
1084                                                                                                                    
1085      /**                                                                                                           
1086       * Set this as the current Launcher activity object for the loader.                                           
1087       */                                                                                                           
1088      public void initialize(Callbacks callbacks) {                                                                 
1089          synchronized (mLock) {                                                                                    
1090              mCallbacks = new WeakReference<Callbacks>(callbacks);                                                 
1091          }                                                                                                         
1092      }                                                                                                             
1093                                                                                                                    
1094      /**                                                                                                           
1095       * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                                 
1096       * ACTION_PACKAGE_CHANGED.                                                                                    
1097       */                                                                                                           
1098      @Override                                                                                                     
1099      public void onReceive(Context context, Intent intent) {                                                       
1100          if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);                                              
1101                                                                                                                    
1102          final String action = intent.getAction();                                                                 
1103                                                                                                                    
1104          if (Intent.ACTION_PACKAGE_CHANGED.equals(action)                                                          
1105                  || Intent.ACTION_PACKAGE_REMOVED.equals(action)                                                   
1106                  || Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                                  
1107              final String packageName = intent.getData().getSchemeSpecificPart();                                  
1108              final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);                      
1109                                                                                                                    
1110              int op = PackageUpdatedTask.OP_NONE;                                                                  
1111                                                                                                                    
1112              if (packageName == null || packageName.length() == 0) {                                               
1113                  // they sent us a bad intent                                                                      
1114                  return;                                                                                           
1115              }                                                                                                     
1116                                                                                                                    
1117              if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {                                                   
1118                  op = PackageUpdatedTask.OP_UPDATE;                                                                
1119              } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {                                            
1120                  if (!replacing) {                                                                                 
1121                      op = PackageUpdatedTask.OP_REMOVE;                                                            
1122                  }                                                                                                 
1123                  // else, we are replacing the package, so a PACKAGE_ADDED will be sent                            
1124                  // later, we will update the package at this time                                                 
1125              } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                              
1126                  if (!replacing) {                                                                                 
1127                      op = PackageUpdatedTask.OP_ADD;                                                               
1128                  } else {                                                                                          
1129                      op = PackageUpdatedTask.OP_UPDATE;                                                            
1130                  }                                                                                                 
1131              }                                                                                                     
1132                                                                                                                    
1133              if (op != PackageUpdatedTask.OP_NONE) {                                                               
1134                  enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));                  
1135              }                                                                                                     
1136                                                                                                                    
1137          } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {                                
1138              final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);                      
1139              String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);                    
1140              if (!replacing) {                                                                                     
1141                  enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));               
1142                  if (mAppsCanBeOnRemoveableStorage) {                                                              
1143                      // Only rebind if we support removable storage.  It catches the case where                    
1144                      // apps on the external sd card need to be reloaded                                           
1145                      startLoaderFromBackground();                                                                  
1146                  }                                                                                                 
1147              } else {                                                                                              
1148                  // If we are replacing then just update the packages in the list                                  
1149                  enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                        
1150                          packages));                                                                               
1151              }                                                                                                     
1152          } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {                              
1153              final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);                      
1154              if (!replacing) {                                                                                     
1155                  String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);                
1156                  enqueuePackageUpdated(new PackageUpdatedTask(                                                     
1157                              PackageUpdatedTask.OP_UNAVAILABLE, packages));                                        
1158              }                                                                                                     
1159              // else, we are replacing the packages, so ignore this event and wait for                             
1160              // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time                                
1161          } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                                 
1162              // If we have changed locale we need to clear out the labels in all apps/workspace.                   
1163              forceReload();                                                                                        
1164          } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                          
1165               // Check if configuration change was an mcc/mnc change which would affect app resources              
1166               // and we would need to clear out the labels in all apps/workspace. Same handling as                 
1167               // above for ACTION_LOCALE_CHANGED                                                                   
1168               Configuration currentConfig = context.getResources().getConfiguration();                             
1169               if (mPreviousConfigMcc != currentConfig.mcc) {                                                       
1170                     Log.d(TAG, "Reload apps on config change. curr_mcc:"                                           
1171                         + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                                   
1172                     forceReload();                                                                                 
1173               }                                                                                                    
1174               // Update previousConfig                                                                             
1175               mPreviousConfigMcc = currentConfig.mcc;                                                              
1176          } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                          
1177                     SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                              
1178              if (mCallbacks != null) {                                                                             
1179                  Callbacks callbacks = mCallbacks.get();                                                           
1180                  if (callbacks != null) {                                                                          
1181                      callbacks.bindSearchablesChanged();                                                           
1182                  }                                                                                                 
1183              }                                                                                                     
1184          }                                                                                                         
1185      }                                                                                                             
1186                                                                                                                    
1187      private void forceReload() {                                                                                  
1188          resetLoadedState(true, true);                                                                             
1189                                                                                                                    
1190          // Do this here because if the launcher activity is running it will be restarted.                         
1191          // If it's not running startLoaderFromBackground will merely tell it that it needs                        
1192          // to reload.                                                                                             
1193          startLoaderFromBackground();                                                                              
1194      }                                                                                                             
1195                                                                                                                    
1196      public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {                      
1197          synchronized (mLock) {                                                                                    
1198              // Stop any existing loaders first, so they don't set mAllAppsLoaded or                               
1199              // mWorkspaceLoaded to true later                                                                     
1200              stopLoaderLocked();                                                                                   
1201              if (resetAllAppsLoaded) mAllAppsLoaded = false;                                                       
1202              if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                                   
1203          }                                                                                                         
1204      }                                                                                                             
1205                                                                                                                    
1206      /**                                                                                                           
1207       * When the launcher is in the background, it's possible for it to miss paired                                
1208       * configuration changes.  So whenever we trigger the loader from the background                              
1209       * tell the launcher that it needs to re-run the loader when it comes back instead                            
1210       * of doing it now.                                                                                           
1211       */                                                                                                           
1212      public void startLoaderFromBackground() {                                                                     
1213          boolean runLoader = false;                                                                                
1214          if (mCallbacks != null) {                                                                                 
1215              Callbacks callbacks = mCallbacks.get();                                                               
1216              if (callbacks != null) {                                                                              
1217                  // Only actually run the loader if they're not paused.                                            
1218                  if (!callbacks.setLoadOnResume()) {                                                               
1219                      runLoader = true;                                                                             
1220                  }                                                                                                 
1221              }                                                                                                     
1222          }                                                                                                         
1223          if (runLoader) {                                                                                          
1224              startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                                   
1225          }                                                                                                         
1226      }                                                                                                             
1227                                                                                                                    
1228      // If there is already a loader task running, tell it to stop.                                                
1229      // returns true if isLaunching() was true on the old task                                                     
1230      private boolean stopLoaderLocked() {                                                                          
1231          boolean isLaunching = false;                                                                              
1232          LoaderTask oldTask = mLoaderTask;                                                                         
1233          if (oldTask != null) {                                                                                    
1234              if (oldTask.isLaunching()) {                                                                          
1235                  isLaunching = true;                                                                               
1236              }                                                                                                     
1237              oldTask.stopLocked();                                                                                 
1238          }                                                                                                         
1239          return isLaunching;                                                                                       
1240      }                                                                                                             
1241                                                                                                                    
1242      public void startLoader(boolean isLaunching, int synchronousBindPage) {                                       
1243          startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                          
1244      }                                                                                                             
1245                                                                                                                    
1246      public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {                        
1247          synchronized (mLock) {                                                                                    
1248              if (DEBUG_LOADERS) {                                                                                  
1249                  Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                             
1250              }                                                                                                     
1251                                                                                                                    
1252              // Clear any deferred bind-runnables from the synchronized load process                               
1253              // We must do this before any loading/binding is scheduled below.                                     
1254              mDeferredBindRunnables.clear();                                                                       
1255                                                                                                                    
1256              // Don't bother to start the thread if we know it's not going to do anything                          
1257              if (mCallbacks != null && mCallbacks.get() != null) {                                                 
1258                  // If there is already one running, tell it to stop.                                              
1259                  // also, don't downgrade isLaunching if we're already running                                     
1260                  isLaunching = isLaunching || stopLoaderLocked();                                                  
1261                  mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                          
1262                  if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                         
1263                          && mAllAppsLoaded && mWorkspaceLoaded) {                                                  
1264                      mLoaderTask.runBindSynchronousPage(synchronousBindPage);                                      
1265                  } else {                                                                                          
1266                      sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                              
1267                      sWorker.post(mLoaderTask);                                                                    
1268                  }                                                                                                 
1269              }                                                                                                     
1270          }                                                                                                         
1271      }                                                                                                             
1272                                                                                                                    
1273      void bindRemainingSynchronousPages() {                                                                        
1274          // Post the remaining side pages to be loaded                                                             
1275          if (!mDeferredBindRunnables.isEmpty()) {                                                                  
1276              for (final Runnable r : mDeferredBindRunnables) {                                                     
1277                  mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                                   
1278              }                                                                                                     
1279              mDeferredBindRunnables.clear();                                                                       
1280          }                                                                                                         
1281      }                                                                                                             
1282                                                                                                                    
1283      public void stopLoader() {                                                                                    
1284          synchronized (mLock) {                                                                                    
1285              if (mLoaderTask != null) {                                                                            
1286                  mLoaderTask.stopLocked();                                                                         
1287              }                                                                                                     
1288          }                                                                                                         
1289      }                                                                                                             
1290                                                                                                                    
1291      /** Loads the workspace screens db into a map of Rank -> ScreenId */                                          
1292      private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {                               
1293          final ContentResolver contentResolver = context.getContentResolver();                                     
1294          final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                     
1295          final Cursor sc = contentResolver.query(screensUri, null, null, null, null);                              
1296          TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();                                     
1297                                                                                                                    
1298          try {                                                                                                     
1299              final int idIndex = sc.getColumnIndexOrThrow(                                                         
1300                      LauncherSettings.WorkspaceScreens._ID);                                                       
1301              final int rankIndex = sc.getColumnIndexOrThrow(                                                       
1302                      LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                               
1303              while (sc.moveToNext()) {                                                                             
1304                  try {                                                                                             
1305                      long screenId = sc.getLong(idIndex);                                                          
1306                      int rank = sc.getInt(rankIndex);                                                              
1307                      orderedScreens.put(rank, screenId);                                                           
1308                  } catch (Exception e) {                                                                           
1309                      Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e, true);  
1310                  }                                                                                                 
1311              }                                                                                                     
1312          } finally {                                                                                               
1313              sc.close();                                                                                           
1314          }                                                                                                         
1315                                                                                                                    
1316          // Log to disk                                                                                            
1317          Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);                                    
1318          ArrayList<String> orderedScreensPairs= new ArrayList<String>();                                           
1319          for (Integer i : orderedScreens.keySet()) {                                                               
1320              orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");                              
1321          }                                                                                                         
1322          Launcher.addDumpLog(TAG, "11683562 -   screens: " +                                                       
1323                  TextUtils.join(", ", orderedScreensPairs), true);                                                 
1324          return orderedScreens;                                                                                    
1325      }                                                                                                             
1326                                                                                                                    
1327      public boolean isAllAppsLoaded() {                                                                            
1328          return mAllAppsLoaded;                                                                                    
1329      }                                                                                                             
1330                                                                                                                    
1331      boolean isLoadingWorkspace() {                                                                                
1332          synchronized (mLock) {                                                                                    
1333              if (mLoaderTask != null) {                                                                            
1334                  return mLoaderTask.isLoadingWorkspace();                                                          
1335              }                                                                                                     
1336          }                                                                                                         
1337          return false;                                                                                             
1338      }                                                                                                             
1339                                                                                                                    
1340      /**                                                                                                           
1341       * Runnable for the thread that loads the contents of the launcher:                                           
1342       *   - workspace icons                                                                                        
1343       *   - widgets                                                                                                
1344       *   - all apps icons                                                                                         
1345       */                                                                                                           
1346      private class LoaderTask implements Runnable {                                                                
1347          private Context mContext;                                                                                 
1348          private boolean mIsLaunching;                                                                             
1349          private boolean mIsLoadingAndBindingWorkspace;                                                            
1350          private boolean mStopped;                                                                                 
1351          private boolean mLoadAndBindStepFinished;                                                                 
1352          private int mFlags;                                                                                       
1353                                                                                                                    
1354          private HashMap<Object, CharSequence> mLabelCache;                                                        
1355                                                                                                                    
1356          LoaderTask(Context context, boolean isLaunching, int flags) {                                             
1357              mContext = context;                                                                                   
1358              mIsLaunching = isLaunching;                                                                           
1359              mLabelCache = new HashMap<Object, CharSequence>();                                                    
1360              mFlags = flags;                                                                                       
1361          }                                                                                                         
1362                                                                                                                    
1363          boolean isLaunching() {                                                                                   
1364              return mIsLaunching;                                                                                  
1365          }                                                                                                         
1366                                                                                                                    
1367          boolean isLoadingWorkspace() {                                                                            
1368              return mIsLoadingAndBindingWorkspace;                                                                 
1369          }                                                                                                         
1370                                                                                                                    
1371          /** Returns whether this is an upgrade path */                                                            
1372          private boolean loadAndBindWorkspace() {                                                                  
1373              mIsLoadingAndBindingWorkspace = true;                                                                 
1374                                                                                                                    
1375              // Load the workspace                                                                                 
1376              if (DEBUG_LOADERS) {                                                                                  
1377                  Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                          
1378              }                                                                                                     
1379                                                                                                                    
1380              boolean isUpgradePath = false;                                                                        
1381              if (!mWorkspaceLoaded) {                                                                              
1382                  isUpgradePath = loadWorkspace();                                                                  
1383                  synchronized (LoaderTask.this) {                                                                  
1384                      if (mStopped) {                                                                               
1385                          return isUpgradePath;                                                                     
1386                      }                                                                                             
1387                      mWorkspaceLoaded = true;                                                                      
1388                  }                                                                                                 
1389              }                                                                                                     
1390                                                                                                                    
1391              // Bind the workspace                                                                                 
1392              bindWorkspace(-1, isUpgradePath);                                                                     
1393              return isUpgradePath;                                                                                 
1394          }                                                                                                         
1395                                                                                                                    
1396          private void waitForIdle() {                                                                              
1397              // Wait until the either we're stopped or the other threads are done.                                 
1398              // This way we don't start loading all apps until the workspace has settled                           
1399              // down.                                                                                              
1400              synchronized (LoaderTask.this) {                                                                      
1401                  final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                    
1402                                                                                                                    
1403                  mHandler.postIdle(new Runnable() {                                                                
1404                          public void run() {                                                                       
1405                              synchronized (LoaderTask.this) {                                                      
1406                                  mLoadAndBindStepFinished = true;                                                  
1407                                  if (DEBUG_LOADERS) {                                                              
1408                                      Log.d(TAG, "done with previous binding step");                                
1409                                  }                                                                                 
1410                                  LoaderTask.this.notify();                                                         
1411                              }                                                                                     
1412                          }                                                                                         
1413                      });                                                                                           
1414                                                                                                                    
1415                  while (!mStopped && !mLoadAndBindStepFinished && !mFlushingWorkerThread) {                        
1416                      try {                                                                                         
1417                          // Just in case mFlushingWorkerThread changes but we aren't woken up,                     
1418                          // wait no longer than 1sec at a time                                                     
1419                          this.wait(1000);                                                                          
1420                      } catch (InterruptedException ex) {                                                           
1421                          // Ignore                                                                                 
1422                      }                                                                                             
1423                  }                                                                                                 
1424                  if (DEBUG_LOADERS) {                                                                              
1425                      Log.d(TAG, "waited "                                                                          
1426                              + (SystemClock.uptimeMillis()-workspaceWaitTime)                                      
1427                              + "ms for previous step to finish binding");                                          
1428                  }                                                                                                 
1429              }                                                                                                     
1430          }                                                                                                         
1431                                                                                                                    
1432          void runBindSynchronousPage(int synchronousBindPage) {                                                    
1433              if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                          
1434                  // Ensure that we have a valid page index to load synchronously                                   
1435                  throw new RuntimeException("Should not call runBindSynchronousPage() without " +                  
1436                          "valid page index");                                                                      
1437              }                                                                                                     
1438              if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                           
1439                  // Ensure that we don't try and bind a specified page when the pages have not been                
1440                  // loaded already (we should load everything asynchronously in that case)                         
1441                  throw new RuntimeException("Expecting AllApps and Workspace to be loaded");                       
1442              }                                                                                                     
1443              synchronized (mLock) {                                                                                
1444                  if (mIsLoaderTaskRunning) {                                                                       
1445                      // Ensure that we are never running the background loading at this point since                
1446                      // we also touch the background collections                                                   
1447                      throw new RuntimeException("Error! Background loading is already running");                   
1448                  }                                                                                                 
1449              }                                                                                                     
1450                                                                                                                    
1451              // XXX: Throw an exception if we are already loading (since we touch the worker thread                
1452              //      data structures, we can't allow any other thread to touch that data, but because              
1453              //      this call is synchronous, we can get away with not locking).                                  
1454                                                                                                                    
1455              // The LauncherModel is static in the LauncherAppState and mHandler may have queued                   
1456              // operations from the previous activity.  We need to ensure that all queued operations               
1457              // are executed before any synchronous binding work is done.                                          
1458              mHandler.flush();                                                                                     
1459                                                                                                                    
1460              // Divide the set of loaded items into those that we are binding synchronously, and                   
1461              // everything else that is to be bound normally (asynchronously).                                     
1462              bindWorkspace(synchronousBindPage, false);                                                            
1463              // XXX: For now, continue posting the binding of AllApps as there are other issues that               
1464              //      arise from that.                                                                              
1465              onlyBindAllApps();                                                                                    
1466          }                                                                                                         
1467                                                                                                                    
1468          public void run() {                                                                                       
1469              boolean isUpgrade = false;                                                                            
1470                                                                                                                    
1471              synchronized (mLock) {                                                                                
1472                  mIsLoaderTaskRunning = true;                                                                      
1473              }                                                                                                     
1474              // Optimize for end-user experience: if the Launcher is up and // running with the                    
1475              // All Apps interface in the foreground, load All Apps first. Otherwise, load the                     
1476              // workspace first (default).                                                                         
1477              keep_running: {                                                                                       
1478                  // Elevate priority when Home launches for the first time to avoid                                
1479                  // starving at boot time. Staring at a blank home is not cool.                                    
1480                  synchronized (mLock) {                                                                            
1481                      if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                                 
1482                              (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                           
1483                      android.os.Process.setThreadPriority(mIsLaunching                                             
1484                              ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);              
1485                  }                                                                                                 
1486                  if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                                       
1487                  isUpgrade = loadAndBindWorkspace();                                                               
1488                                                                                                                    
1489                  if (mStopped) {                                                                                   
1490                      break keep_running;                                                                           
1491                  }                                                                                                 
1492                                                                                                                    
1493                  // Whew! Hard work done.  Slow us down, and wait until the UI thread has                          
1494                  // settled down.                                                                                  
1495                  synchronized (mLock) {                                                                            
1496                      if (mIsLaunching) {                                                                           
1497                          if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                   
1498                          android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                 
1499                      }                                                                                             
1500                  }                                                                                                 
1501                  waitForIdle();                                                                                    
1502                                                                                                                    
1503                  // second step                                                                                    
1504                  if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                                        
1505                  loadAndBindAllApps();                                                                             
1506                                                                                                                    
1507                  // Restore the default thread priority after we are done loading items                            
1508                  synchronized (mLock) {                                                                            
1509                      android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                        
1510                  }                                                                                                 
1511              }                                                                                                     
1512                                                                                                                    
1513              // Update the saved icons if necessary                                                                
1514              if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                            
1515              synchronized (sBgLock) {                                                                              
1516                  for (Object key : sBgDbIconCache.keySet()) {                                                      
1517                      updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));                       
1518                  }                                                                                                 
1519                  sBgDbIconCache.clear();                                                                           
1520              }                                                                                                     
1521                                                                                                                    
1522              if (LauncherAppState.isDisableAllApps()) {                                                            
1523                  // Ensure that all the applications that are in the system are                                    
1524                  // represented on the home screen.                                                                
1525                  if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {                                                
1526                      verifyApplications();                                                                         
1527                  }                                                                                                 
1528              }                                                                                                     
1529                                                                                                                    
1530              // Clear out this reference, otherwise we end up holding it until all of the                          
1531              // callback runnables are done.                                                                       
1532              mContext = null;                                                                                      
1533                                                                                                                    
1534              synchronized (mLock) {                                                                                
1535                  // If we are still the last one to be scheduled, remove ourselves.                                
1536                  if (mLoaderTask == this) {                                                                        
1537                      mLoaderTask = null;                                                                           
1538                  }                                                                                                 
1539                  mIsLoaderTaskRunning = false;                                                                     
1540              }                                                                                                     
1541          }                                                                                                         
1542                                                                                                                    
1543          public void stopLocked() {                                                                                
1544              synchronized (LoaderTask.this) {                                                                      
1545                  mStopped = true;                                                                                  
1546                  this.notify();                                                                                    
1547              }                                                                                                     
1548          }                                                                                                         
1549                                                                                                                    
1550          /**                                                                                                       
1551           * Gets the callbacks object.  If we've been stopped, or if the launcher object                           
1552           * has somehow been garbage collected, return null instead.  Pass in the Callbacks                        
1553           * object that was around when the deferred message was scheduled, and if there's                         
1554           * a new Callbacks object around then also return null.  This will save us from                           
1555           * calling onto it with data that will be ignored.                                                        
1556           */                                                                                                       
1557          Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                                       
1558              synchronized (mLock) {                                                                                
1559                  if (mStopped) {                                                                                   
1560                      return null;                                                                                  
1561                  }                                                                                                 
1562                                                                                                                    
1563                  if (mCallbacks == null) {                                                                         
1564                      return null;                                                                                  
1565                  }                                                                                                 
1566                                                                                                                    
1567                  final Callbacks callbacks = mCallbacks.get();                                                     
1568                  if (callbacks != oldCallbacks) {                                                                  
1569                      return null;                                                                                  
1570                  }                                                                                                 
1571                  if (callbacks == null) {                                                                          
1572                      Log.w(TAG, "no mCallbacks");                                                                  
1573                      return null;                                                                                  
1574                  }                                                                                                 
1575                                                                                                                    
1576                  return callbacks;                                                                                 
1577              }                                                                                                     
1578          }                                                                                                         
1579                                                                                                                    
1580          private void verifyApplications() {                                                                       
1581              final Context context = mApp.getContext();                                                            
1582                                                                                                                    
1583              // Cross reference all the applications in our apps list with items in the workspace                  
1584              ArrayList<ItemInfo> tmpInfos;                                                                         
1585              ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                                
1586              synchronized (sBgLock) {                                                                              
1587                  for (AppInfo app : mBgAllAppsList.data) {                                                         
1588                      tmpInfos = getItemInfoForComponentName(app.componentName);                                    
1589                      if (tmpInfos.isEmpty()) {                                                                     
1590                          // We are missing an application icon, so add this to the workspace                       
1591                          added.add(app);                                                                           
1592                          // This is a rare event, so lets log it                                                   
1593                          Log.e(TAG, "Missing Application on load: " + app);                                        
1594                      }                                                                                             
1595                  }                                                                                                 
1596              }                                                                                                     
1597              if (!added.isEmpty()) {                                                                               
1598 -                addAndBindAddedWorkspaceApps(context, added);                                                     
1599 +                Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                      
1600 +                addAndBindAddedApps(context, added, cb, new ArrayList<AppInfo>());                                
1601              }                                                                                                     
1602          }                                                                                                         
1603                                                                                                                    
1604          // check & update map of what's occupied; used to discard overlapping/invalid items                       
1605          private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item,                   
1606                                             AtomicBoolean deleteOnInvalidPlacement) {                              
1607              LauncherAppState app = LauncherAppState.getInstance();                                                
1608              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1609              final int countX = (int) grid.numColumns;                                                             
1610              final int countY = (int) grid.numRows;                                                                
1611                                                                                                                    
1612              long containerIndex = item.screenId;                                                                  
1613              if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
1614                  // Return early if we detect that an item is under the hotseat button                             
1615                  if (mCallbacks == null ||                                                                         
1616                          mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                              
1617                      deleteOnInvalidPlacement.set(true);                                                           
1618                      Log.e(TAG, "Error loading shortcut into hotseat " + item                                      
1619                              + " into position (" + item.screenId + ":" + item.cellX + ","                         
1620                              + item.cellY + ") occupied by all apps");                                             
1621                      return false;                                                                                 
1622                  }                                                                                                 
1623                                                                                                                    
1624                  final ItemInfo[][] hotseatItems =                                                                 
1625                          occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);                        
1626                                                                                                                    
1627                  if (item.screenId >= grid.numHotseatIcons) {                                                      
1628                      Log.e(TAG, "Error loading shortcut " + item                                                   
1629                              + " into hotseat position " + item.screenId                                           
1630                              + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)                     
1631                              + ")");                                                                               
1632                      return false;                                                                                 
1633                  }                                                                                                 
1634                                                                                                                    
1635                  if (hotseatItems != null) {                                                                       
1636                      if (hotseatItems[(int) item.screenId][0] != null) {                                           
1637                          Log.e(TAG, "Error loading shortcut into hotseat " + item                                  
1638                                  + " into position (" + item.screenId + ":" + item.cellX + ","                     
1639                                  + item.cellY + ") occupied by "                                                   
1640                                  + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)                      
1641                                  [(int) item.screenId][0]);                                                        
1642                              return false;                                                                         
1643                      } else {                                                                                      
1644                          hotseatItems[(int) item.screenId][0] = item;                                              
1645                          return true;                                                                              
1646                      }                                                                                             
1647                  } else {                                                                                          
1648                      final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];                       
1649                      items[(int) item.screenId][0] = item;                                                         
1650                      occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);                     
1651                      return true;                                                                                  
1652                  }                                                                                                 
1653              } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                          
1654                  // Skip further checking if it is not the hotseat or workspace container                          
1655                  return true;                                                                                      
1656              }                                                                                                     
1657                                                                                                                    
1658              if (!occupied.containsKey(item.screenId)) {                                                           
1659                  ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                                        
1660                  occupied.put(item.screenId, items);                                                               
1661              }                                                                                                     
1662                                                                                                                    
1663              final ItemInfo[][] screens = occupied.get(item.screenId);                                             
1664              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
1665                      item.cellX < 0 || item.cellY < 0 ||                                                           
1666                      item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {                       
1667                  Log.e(TAG, "Error loading shortcut " + item                                                       
1668                          + " into cell (" + containerIndex + "-" + item.screenId + ":"                             
1669                          + item.cellX + "," + item.cellY                                                           
1670                          + ") out of screen bounds ( " + countX + "x" + countY + ")");                             
1671                  return false;                                                                                     
1672              }                                                                                                     
1673                                                                                                                    
1674              // Check if any workspace icons overlap with each other                                               
1675              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1676                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1677                      if (screens[x][y] != null) {                                                                  
1678                          Log.e(TAG, "Error loading shortcut " + item                                               
1679                              + " into cell (" + containerIndex + "-" + item.screenId + ":"                         
1680                              + x + "," + y                                                                         
1681                              + ") occupied by "                                                                    
1682                              + screens[x][y]);                                                                     
1683                          return false;                                                                             
1684                      }                                                                                             
1685                  }                                                                                                 
1686              }                                                                                                     
1687              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1688                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1689                      screens[x][y] = item;                                                                         
1690                  }                                                                                                 
1691              }                                                                                                     
1692                                                                                                                    
1693              return true;                                                                                          
1694          }                                                                                                         
1695                                                                                                                    
1696          /** Clears all the sBg data structures */                                                                 
1697          private void clearSBgDataStructures() {                                                                   
1698              synchronized (sBgLock) {                                                                              
1699                  sBgWorkspaceItems.clear();                                                                        
1700                  sBgAppWidgets.clear();                                                                            
1701                  sBgFolders.clear();                                                                               
1702                  sBgItemsIdMap.clear();                                                                            
1703                  sBgDbIconCache.clear();                                                                           
1704                  sBgWorkspaceScreens.clear();                                                                      
1705              }                                                                                                     
1706          }                                                                                                         
1707                                                                                                                    
1708          /** Returns whether this is an upgrade path */                                                            
1709          private boolean loadWorkspace() {                                                                         
1710              // Log to disk                                                                                        
1711              Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                         
1712                                                                                                                    
1713              final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                        
1714                                                                                                                    
1715              final Context context = mContext;                                                                     
1716              final ContentResolver contentResolver = context.getContentResolver();                                 
1717              final PackageManager manager = context.getPackageManager();                                           
1718              final AppWidgetManager widgets = AppWidgetManager.getInstance(context);                               
1719              final boolean isSafeMode = manager.isSafeMode();                                                      
1720                                                                                                                    
1721              LauncherAppState app = LauncherAppState.getInstance();                                                
1722              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1723              int countX = (int) grid.numColumns;                                                                   
1724              int countY = (int) grid.numRows;                                                                      
1725                                                                                                                    
1726              if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                                    
1727                  Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);                     
1728                  LauncherAppState.getLauncherProvider().deleteDatabase();                                          
1729              }                                                                                                     
1730                                                                                                                    
1731              if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                                  
1732                  // append the user's Launcher2 shortcuts                                                          
1733                  Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);                        
1734                  LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                               
1735              } else {                                                                                              
1736                  // Make sure the default workspace is loaded                                                      
1737                  Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);                      
1738                  LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);                        
1739              }                                                                                                     
1740                                                                                                                    
1741              // Check if we need to do any upgrade-path logic                                                      
1742              // (Includes having just imported default favorites)                                                  
1743              boolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb();                       
1744                                                                                                                    
1745              // Log to disk                                                                                        
1746              Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);                           
1747                                                                                                                    
1748              synchronized (sBgLock) {                                                                              
1749                  clearSBgDataStructures();                                                                         
1750                                                                                                                    
1751                  final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                                      
1752                  final ArrayList<Long> restoredRows = new ArrayList<Long>();                                       
1753                  final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                                    
1754                  if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                                
1755                  final Cursor c = contentResolver.query(contentUri, null, null, null, null);                       
1756                                                                                                                    
1757                  // +1 for the hotseat (it can be larger than the workspace)                                       
1758                  // Load workspace in reverse order to ensure that latest items are loaded first (and              
1759                  // before any earlier duplicates)                                                                 
1760                  final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();                   
1761                                                                                                                    
1762                  try {                                                                                             
1763                      final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);                  
1764                      final int intentIndex = c.getColumnIndexOrThrow                                               
1765                              (LauncherSettings.Favorites.INTENT);                                                  
1766                      final int titleIndex = c.getColumnIndexOrThrow                                                
1767                              (LauncherSettings.Favorites.TITLE);                                                   
1768                      final int iconTypeIndex = c.getColumnIndexOrThrow(                                            
1769                              LauncherSettings.Favorites.ICON_TYPE);                                                
1770                      final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);               
1771                      final int iconPackageIndex = c.getColumnIndexOrThrow(                                         
1772                              LauncherSettings.Favorites.ICON_PACKAGE);                                             
1773                      final int iconResourceIndex = c.getColumnIndexOrThrow(                                        
1774                              LauncherSettings.Favorites.ICON_RESOURCE);                                            
1775                      final int containerIndex = c.getColumnIndexOrThrow(                                           
1776                              LauncherSettings.Favorites.CONTAINER);                                                
1777                      final int itemTypeIndex = c.getColumnIndexOrThrow(                                            
1778                              LauncherSettings.Favorites.ITEM_TYPE);                                                
1779                      final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                         
1780                              LauncherSettings.Favorites.APPWIDGET_ID);                                             
1781                      final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                                   
1782                              LauncherSettings.Favorites.APPWIDGET_PROVIDER);                                       
1783                      final int screenIndex = c.getColumnIndexOrThrow(                                              
1784                              LauncherSettings.Favorites.SCREEN);                                                   
1785                      final int cellXIndex = c.getColumnIndexOrThrow                                                
1786                              (LauncherSettings.Favorites.CELLX);                                                   
1787                      final int cellYIndex = c.getColumnIndexOrThrow                                                
1788                              (LauncherSettings.Favorites.CELLY);                                                   
1789                      final int spanXIndex = c.getColumnIndexOrThrow                                                
1790                              (LauncherSettings.Favorites.SPANX);                                                   
1791                      final int spanYIndex = c.getColumnIndexOrThrow(                                               
1792                              LauncherSettings.Favorites.SPANY);                                                    
1793                      final int restoredIndex = c.getColumnIndexOrThrow(                                            
1794                              LauncherSettings.Favorites.RESTORED);                                                 
1795                      //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);               
1796                      //final int displayModeIndex = c.getColumnIndexOrThrow(                                       
1797                      //        LauncherSettings.Favorites.DISPLAY_MODE);                                           
1798                                                                                                                    
1799                      ShortcutInfo info;                                                                            
1800                      String intentDescription;                                                                     
1801                      LauncherAppWidgetInfo appWidgetInfo;                                                          
1802                      int container;                                                                                
1803                      long id;                                                                                      
1804                      Intent intent;                                                                                
1805                                                                                                                    
1806                      while (!mStopped && c.moveToNext()) {                                                         
1807                          AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);                        
1808                          try {                                                                                     
1809                              int itemType = c.getInt(itemTypeIndex);                                               
1810                              boolean restored = 0 != c.getInt(restoredIndex);                                      
1811                                                                                                                    
1812                              switch (itemType) {                                                                   
1813                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1814                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1815                                  id = c.getLong(idIndex);                                                          
1816                                  intentDescription = c.getString(intentIndex);                                     
1817                                  try {                                                                             
1818                                      intent = Intent.parseUri(intentDescription, 0);                               
1819                                      ComponentName cn = intent.getComponent();                                     
1820                                      if (cn != null && !isValidPackageComponent(manager, cn)) {                    
1821                                          if (restored) {                                                           
1822                                              // might be installed later                                           
1823                                              Launcher.addDumpLog(TAG,                                              
1824                                                      "package not yet restored: " + cn, true);                     
1825                                          } else {                                                                  
1826                                              if (!mAppsCanBeOnRemoveableStorage) {                                 
1827                                                  // Log the invalid package, and remove it                         
1828                                                  Launcher.addDumpLog(TAG,                                          
1829                                                          "Invalid package removed: " + cn, true);                  
1830                                                  itemsToRemove.add(id);                                            
1831                                              } else {                                                              
1832                                                  // If apps can be on external storage, then we just               
1833                                                  // leave them for the user to remove (maybe add                   
1834                                                  // visual treatment to it)                                        
1835                                                  Launcher.addDumpLog(TAG,                                          
1836                                                          "Invalid package found: " + cn, true);                    
1837                                              }                                                                     
1838                                              continue;                                                             
1839                                          }                                                                         
1840                                      } else if (restored) {                                                        
1841                                          // no special handling necessary for this restored item                   
1842                                          restoredRows.add(id);                                                     
1843                                          restored = false;                                                         
1844                                      }                                                                             
1845                                  } catch (URISyntaxException e) {                                                  
1846                                      Launcher.addDumpLog(TAG,                                                      
1847                                              "Invalid uri: " + intentDescription, true);                           
1848                                      continue;                                                                     
1849                                  }                                                                                 
1850                                                                                                                    
1851                                  if (restored) {                                                                   
1852                                      Launcher.addDumpLog(TAG,                                                      
1853                                              "constructing info for partially restored package",                   
1854                                              true);                                                                
1855                                      info = getRestoredItemInfo(c, titleIndex);                                    

1856                                      intent = getRestoredItemIntent(c, context, intent);                           
1857                                  } else if (itemType ==                                                            
1858                                          LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                       
1859                                      info = getShortcutInfo(manager, intent, context, c, iconIndex,                
1860                                              titleIndex, mLabelCache);                                             
1861                                  } else {                                                                          
1862                                      info = getShortcutInfo(c, context, iconTypeIndex,                             
1863                                              iconPackageIndex, iconResourceIndex, iconIndex,                       
1864                                              titleIndex);                                                          
1865                                                                                                                    
1866                                      // App shortcuts that used to be automatically added to Launcher              
1867                                      // didn't always have the correct intent flags set, so do that                
1868                                      // here                                                                       
1869                                      if (intent.getAction() != null &&                                             
1870                                          intent.getCategories() != null &&                                         
1871                                          intent.getAction().equals(Intent.ACTION_MAIN) &&                          
1872                                          intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {              
1873                                          intent.addFlags(                                                          
1874                                              Intent.FLAG_ACTIVITY_NEW_TASK |                                       
1875                                              Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                           
1876                                      }                                                                             
1877                                  }                                                                                 
1878                                                                                                                    
1879                                  if (info != null) {                                                               
1880                                      info.id = id;                                                                 
1881                                      info.intent = intent;                                                         
1882                                      container = c.getInt(containerIndex);                                         
1883                                      info.container = container;                                                   
1884                                      info.screenId = c.getInt(screenIndex);                                        
1885                                      info.cellX = c.getInt(cellXIndex);                                            
1886                                      info.cellY = c.getInt(cellYIndex);                                            
1887                                      info.spanX = 1;                                                               
1888                                      info.spanY = 1;                                                               
1889                                                                                                                    
1890                                      // check & update map of what's occupied                                      
1891                                      deleteOnInvalidPlacement.set(false);                                          
1892                                      if (!checkItemPlacement(occupied, info, deleteOnInvalidPlacement)) {          
1893                                          if (deleteOnInvalidPlacement.get()) {                                     
1894                                              itemsToRemove.add(id);                                                
1895                                          }                                                                         
1896                                          break;                                                                    
1897                                      }                                                                             
1898                                                                                                                    
1899                                      switch (container) {                                                          
1900                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
1901                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
1902                                          sBgWorkspaceItems.add(info);                                              
1903                                          break;                                                                    
1904                                      default:                                                                      
1905                                          // Item is in a user folder                                               
1906                                          FolderInfo folderInfo =                                                   
1907                                                  findOrMakeFolder(sBgFolders, container);                          
1908                                          folderInfo.add(info);                                                     
1909                                          break;                                                                    
1910                                      }                                                                             
1911                                      sBgItemsIdMap.put(info.id, info);                                             
1912                                                                                                                    
1913                                      // now that we've loaded everthing re-save it with the                        
1914                                      // icon in case it disappears somehow.                                        
1915                                      queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);                     
1916                                  } else {                                                                          
1917                                      throw new RuntimeException("Unexpected null ShortcutInfo");                   
1918                                  }                                                                                 
1919                                  break;                                                                            
1920                                                                                                                    
1921                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
1922                                  id = c.getLong(idIndex);                                                          
1923                                  FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                         
1924                                                                                                                    
1925                                  folderInfo.title = c.getString(titleIndex);                                       
1926                                  folderInfo.id = id;                                                               
1927                                  container = c.getInt(containerIndex);                                             
1928                                  folderInfo.container = container;                                                 
1929                                  folderInfo.screenId = c.getInt(screenIndex);                                      
1930                                  folderInfo.cellX = c.getInt(cellXIndex);                                          
1931                                  folderInfo.cellY = c.getInt(cellYIndex);                                          
1932                                  folderInfo.spanX = 1;                                                             
1933                                  folderInfo.spanY = 1;                                                             
1934                                                                                                                    
1935                                  // check & update map of what's occupied                                          
1936                                  deleteOnInvalidPlacement.set(false);                                              
1937                                  if (!checkItemPlacement(occupied, folderInfo,                                     
1938                                          deleteOnInvalidPlacement)) {                                              
1939                                      if (deleteOnInvalidPlacement.get()) {                                         
1940                                          itemsToRemove.add(id);                                                    
1941                                      }                                                                             
1942                                      break;                                                                        
1943                                  }                                                                                 
1944                                                                                                                    
1945                                  switch (container) {                                                              
1946                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
1947                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
1948                                          sBgWorkspaceItems.add(folderInfo);                                        
1949                                          break;                                                                    
1950                                  }                                                                                 
1951                                                                                                                    
1952                                  if (restored) {                                                                   
1953                                      // no special handling required for restored folders                          
1954                                      restoredRows.add(id);                                                         
1955                                  }                                                                                 
1956                                                                                                                    
1957                                  sBgItemsIdMap.put(folderInfo.id, folderInfo);                                     
1958                                  sBgFolders.put(folderInfo.id, folderInfo);                                        
1959                                  break;                                                                            
1960                                                                                                                    
1961                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
1962                                  // Read all Launcher-specific widget details                                      
1963                                  int appWidgetId = c.getInt(appWidgetIdIndex);                                     
1964                                  String savedProvider = c.getString(appWidgetProviderIndex);                       
1965                                                                                                                    
1966                                  id = c.getLong(idIndex);                                                          
1967                                                                                                                    
1968                                  final AppWidgetProviderInfo provider =                                            
1969                                          widgets.getAppWidgetInfo(appWidgetId);                                    
1970                                                                                                                    
1971                                  if (!isSafeMode && (provider == null || provider.provider == null ||              
1972                                          provider.provider.getPackageName() == null)) {                            
1973                                      String log = "Deleting widget that isn't installed anymore: id="              
1974                                          + id + " appWidgetId=" + appWidgetId;                                     
1975                                      Log.e(TAG, log);                                                              
1976                                      Launcher.addDumpLog(TAG, log, false);                                         
1977                                      itemsToRemove.add(id);                                                        
1978                                  } else {                                                                          
1979                                      appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                        
1980                                              provider.provider);                                                   
1981                                      appWidgetInfo.id = id;                                                        
1982                                      appWidgetInfo.screenId = c.getInt(screenIndex);                               
1983                                      appWidgetInfo.cellX = c.getInt(cellXIndex);                                   
1984                                      appWidgetInfo.cellY = c.getInt(cellYIndex);                                   
1985                                      appWidgetInfo.spanX = c.getInt(spanXIndex);                                   
1986                                      appWidgetInfo.spanY = c.getInt(spanYIndex);                                   
1987                                      int[] minSpan = Launcher.getMinSpanForWidget(context, provider);              
1988                                      appWidgetInfo.minSpanX = minSpan[0];                                          
1989                                      appWidgetInfo.minSpanY = minSpan[1];                                          
1990                                                                                                                    
1991                                      container = c.getInt(containerIndex);                                         
1992                                      if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&              
1993                                          container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {              
1994                                          Log.e(TAG, "Widget found where container != " +                           
1995                                              "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");               
1996                                          continue;                                                                 
1997                                      }                                                                             
1998                                                                                                                    
1999                                      appWidgetInfo.container = c.getInt(containerIndex);                           
2000                                      // check & update map of what's occupied                                      
2001                                      deleteOnInvalidPlacement.set(false);                                          
2002                                      if (!checkItemPlacement(occupied, appWidgetInfo,                              
2003                                              deleteOnInvalidPlacement)) {                                          
2004                                          if (deleteOnInvalidPlacement.get()) {                                     
2005                                              itemsToRemove.add(id);                                                
2006                                          }                                                                         
2007                                          break;                                                                    
2008                                      }                                                                             
2009                                      String providerName = provider.provider.flattenToString();                    
2010                                      if (!providerName.equals(savedProvider)) {                                    
2011                                          ContentValues values = new ContentValues();                               
2012                                          values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,                 
2013                                                  providerName);                                                    
2014                                          String where = BaseColumns._ID + "= ?";                                   
2015                                          String[] args = {Integer.toString(c.getInt(idIndex))};                    
2016                                          contentResolver.update(contentUri, values, where, args);                  
2017                                      }                                                                             
2018                                      sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                           
2019                                      sBgAppWidgets.add(appWidgetInfo);                                             
2020                                  }                                                                                 
2021                                  break;                                                                            
2022                              }                                                                                     
2023                          } catch (Exception e) {                                                                   
2024                              Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);               
2025                          }                                                                                         
2026                      }                                                                                             
2027                  } finally {                                                                                       
2028                      if (c != null) {                                                                              
2029                          c.close();                                                                                
2030                      }                                                                                             
2031                  }                                                                                                 
2032                                                                                                                    
2033                  // Break early if we've stopped loading                                                           
2034                  if (mStopped) {                                                                                   
2035                      clearSBgDataStructures();                                                                     
2036                      return false;                                                                                 
2037                  }                                                                                                 
2038                                                                                                                    
2039                  if (itemsToRemove.size() > 0) {                                                                   
2040                      ContentProviderClient client = contentResolver.acquireContentProviderClient(                  
2041                              LauncherSettings.Favorites.CONTENT_URI);                                              
2042                      // Remove dead items                                                                          
2043                      for (long id : itemsToRemove) {                                                               
2044                          if (DEBUG_LOADERS) {                                                                      
2045                              Log.d(TAG, "Removed id = " + id);                                                     
2046                          }                                                                                         
2047                          // Don't notify content observers                                                         
2048                          try {                                                                                     
2049                              client.delete(LauncherSettings.Favorites.getContentUri(id, false),                    
2050                                      null, null);                                                                  
2051                          } catch (RemoteException e) {                                                             
2052                              Log.w(TAG, "Could not remove id = " + id);                                            
2053                          }                                                                                         
2054                      }                                                                                             
2055                  }                                                                                                 
2056                                                                                                                    
2057                  if (restoredRows.size() > 0) {                                                                    
2058                      ContentProviderClient updater = contentResolver.acquireContentProviderClient(                 
2059                              LauncherSettings.Favorites.CONTENT_URI);                                              
2060                      // Update restored items that no longer require special handling                              
2061                      try {                                                                                         
2062                          StringBuilder selectionBuilder = new StringBuilder();                                     
2063                          selectionBuilder.append(LauncherSettings.Favorites._ID);                                  
2064                          selectionBuilder.append(" IN (");                                                         
2065                          selectionBuilder.append(TextUtils.join(", ", restoredRows));                              
2066                          selectionBuilder.append(")");                                                             
2067                          ContentValues values = new ContentValues();                                               
2068                          values.put(LauncherSettings.Favorites.RESTORED, 0);                                       
2069                          updater.update(LauncherSettings.Favorites.CONTENT_URI,                                    
2070                                  values, selectionBuilder.toString(), null);                                       
2071                      } catch (RemoteException e) {                                                                 
2072                          Log.w(TAG, "Could not update restored rows");                                             
2073                      }                                                                                             
2074                  }                                                                                                 
2075                                                                                                                    
2076                  if (loadedOldDb) {                                                                                
2077                      long maxScreenId = 0;                                                                         
2078                      // If we're importing we use the old screen order.                                            
2079                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2080                          long screenId = item.screenId;                                                            
2081                          if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2082                                  !sBgWorkspaceScreens.contains(screenId)) {                                        
2083                              sBgWorkspaceScreens.add(screenId);                                                    
2084                              if (screenId > maxScreenId) {                                                         
2085                                  maxScreenId = screenId;                                                           
2086                              }                                                                                     
2087                          }                                                                                         
2088                      }                                                                                             
2089                      Collections.sort(sBgWorkspaceScreens);                                                        
2090                      // Log to disk                                                                                
2091                      Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);                   
2092                      Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2093                              TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2094                                                                                                                    
2095                      LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);                        
2096                      updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                     
2097                                                                                                                    
2098                      // Update the max item id after we load an old db                                             
2099                      long maxItemId = 0;                                                                           
2100                      // If we're importing we use the old screen order.                                            
2101                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2102                          maxItemId = Math.max(maxItemId, item.id);                                                 
2103                      }                                                                                             
2104                      LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);                            
2105                  } else {                                                                                          
2106                      TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);                     
2107                      for (Integer i : orderedScreens.keySet()) {                                                   
2108                          sBgWorkspaceScreens.add(orderedScreens.get(i));                                           
2109                      }                                                                                             
2110                      // Log to disk                                                                                
2111                      Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2112                              TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2113                                                                                                                    
2114                      // Remove any empty screens                                                                   
2115                      ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                     
2116                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2117                          long screenId = item.screenId;                                                            
2118                          if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2119                                  unusedScreens.contains(screenId)) {                                               
2120                              unusedScreens.remove(screenId);                                                       
2121                          }                                                                                         
2122                      }                                                                                             
2123                                                                                                                    
2124                      // If there are any empty screens remove them, and update.                                    
2125                      if (unusedScreens.size() != 0) {                                                              
2126                          // Log to disk                                                                            
2127                          Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +                 
2128                                  TextUtils.join(", ", unusedScreens), true);                                       
2129                                                                                                                    
2130                          sBgWorkspaceScreens.removeAll(unusedScreens);                                             
2131                          updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                 
2132                      }                                                                                             
2133                  }                                                                                                 
2134                                                                                                                    
2135                  if (DEBUG_LOADERS) {                                                                              
2136                      Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");                   
2137                      Log.d(TAG, "workspace layout: ");                                                             
2138                      int nScreens = occupied.size();                                                               
2139                      for (int y = 0; y < countY; y++) {                                                            
2140                          String line = "";                                                                         
2141                                                                                                                    
2142                          Iterator<Long> iter = occupied.keySet().iterator();                                       
2143                          while (iter.hasNext()) {                                                                  
2144                              long screenId = iter.next();                                                          
2145                              if (screenId > 0) {                                                                   
2146                                  line += " | ";                                                                    
2147                              }                                                                                     
2148                              for (int x = 0; x < countX; x++) {                                                    
2149                                  line += ((occupied.get(screenId)[x][y] != null) ? "#" : ".");                     
2150                              }                                                                                     
2151                          }                                                                                         
2152                          Log.d(TAG, "[ " + line + " ]");                                                           
2153                      }                                                                                             
2154                  }                                                                                                 
2155              }                                                                                                     
2156              return loadedOldDb;                                                                                   
2157          }                                                                                                         
2158                                                                                                                    
2159          /** Filters the set of items who are directly or indirectly (via another container) on the                
2160           * specified screen. */                                                                                   
2161          private void filterCurrentWorkspaceItems(long currentScreenId,                                            
2162                  ArrayList<ItemInfo> allWorkspaceItems,                                                            
2163                  ArrayList<ItemInfo> currentScreenItems,                                                           
2164                  ArrayList<ItemInfo> otherScreenItems) {                                                           
2165              // Purge any null ItemInfos                                                                           
2166              Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                               
2167              while (iter.hasNext()) {                                                                              
2168                  ItemInfo i = iter.next();                                                                         
2169                  if (i == null) {                                                                                  
2170                      iter.remove();                                                                                
2171                  }                                                                                                 
2172              }                                                                                                     
2173                                                                                                                    
2174              // Order the set of items by their containers first, this allows use to walk through the              
2175              // list sequentially, build up a list of containers that are in the specified screen,                 
2176              // as well as all items in those containers.                                                          
2177              Set<Long> itemsOnScreen = new HashSet<Long>();                                                        
2178              Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                                      
2179                  @Override                                                                                         
2180                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2181                      return (int) (lhs.container - rhs.container);                                                 
2182                  }                                                                                                 
2183              });                                                                                                   
2184              for (ItemInfo info : allWorkspaceItems) {                                                             
2185                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                             
2186                      if (info.screenId == currentScreenId) {                                                       
2187                          currentScreenItems.add(info);                                                             
2188                          itemsOnScreen.add(info.id);                                                               
2189                      } else {                                                                                      
2190                          otherScreenItems.add(info);                                                               
2191                      }                                                                                             
2192                  } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                      
2193                      currentScreenItems.add(info);                                                                 
2194                      itemsOnScreen.add(info.id);                                                                   
2195                  } else {                                                                                          
2196                      if (itemsOnScreen.contains(info.container)) {                                                 
2197                          currentScreenItems.add(info);                                                             
2198                          itemsOnScreen.add(info.id);                                                               
2199                      } else {                                                                                      
2200                          otherScreenItems.add(info);                                                               
2201                      }                                                                                             
2202                  }                                                                                                 
2203              }                                                                                                     
2204          }                                                                                                         
2205                                                                                                                    
2206          /** Filters the set of widgets which are on the specified screen. */                                      
2207          private void filterCurrentAppWidgets(long currentScreenId,                                                
2208                  ArrayList<LauncherAppWidgetInfo> appWidgets,                                                      
2209                  ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                            
2210                  ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                            
2211                                                                                                                    
2212              for (LauncherAppWidgetInfo widget : appWidgets) {                                                     
2213                  if (widget == null) continue;                                                                     
2214                  if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                           
2215                          widget.screenId == currentScreenId) {                                                     
2216                      currentScreenWidgets.add(widget);                                                             
2217                  } else {                                                                                          
2218                      otherScreenWidgets.add(widget);                                                               
2219                  }                                                                                                 
2220              }                                                                                                     
2221          }                                                                                                         
2222                                                                                                                    
2223          /** Filters the set of folders which are on the specified screen. */                                      
2224          private void filterCurrentFolders(long currentScreenId,                                                   
2225                  HashMap<Long, ItemInfo> itemsIdMap,                                                               
2226                  HashMap<Long, FolderInfo> folders,                                                                
2227                  HashMap<Long, FolderInfo> currentScreenFolders,                                                   
2228                  HashMap<Long, FolderInfo> otherScreenFolders) {                                                   
2229                                                                                                                    
2230              for (long id : folders.keySet()) {                                                                    
2231                  ItemInfo info = itemsIdMap.get(id);                                                               
2232                  FolderInfo folder = folders.get(id);                                                              
2233                  if (info == null || folder == null) continue;                                                     
2234                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                             
2235                          info.screenId == currentScreenId) {                                                       
2236                      currentScreenFolders.put(id, folder);                                                         
2237                  } else {                                                                                          
2238                      otherScreenFolders.put(id, folder);                                                           
2239                  }                                                                                                 
2240              }                                                                                                     
2241          }                                                                                                         
2242                                                                                                                    
2243          /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to                   
2244           * right) */                                                                                              
2245          private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                            
2246              final LauncherAppState app = LauncherAppState.getInstance();                                          
2247              final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                   
2248              // XXX: review this                                                                                   
2249              Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                         
2250                  @Override                                                                                         
2251                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2252                      int cellCountX = (int) grid.numColumns;                                                       
2253                      int cellCountY = (int) grid.numRows;                                                          
2254                      int screenOffset = cellCountX * cellCountY;                                                   
2255                      int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat               
2256                      long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +                    
2257                              lhs.cellY * cellCountX + lhs.cellX);                                                  
2258                      long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +                    
2259                              rhs.cellY * cellCountX + rhs.cellX);                                                  
2260                      return (int) (lr - rr);                                                                       
2261                  }                                                                                                 
2262              });                                                                                                   
2263          }                                                                                                         
2264                                                                                                                    
2265          private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                           
2266                  final ArrayList<Long> orderedScreens) {                                                           
2267              final Runnable r = new Runnable() {                                                                   
2268                  @Override                                                                                         
2269                  public void run() {                                                                               
2270                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2271                      if (callbacks != null) {                                                                      
2272                          callbacks.bindScreens(orderedScreens);                                                    
2273                      }                                                                                             
2274                  }                                                                                                 
2275              };                                                                                                    
2276              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2277          }                                                                                                         
2278                                                                                                                    
2279          private void bindWorkspaceItems(final Callbacks oldCallbacks,                                             
2280                  final ArrayList<ItemInfo> workspaceItems,                                                         
2281                  final ArrayList<LauncherAppWidgetInfo> appWidgets,                                                
2282                  final HashMap<Long, FolderInfo> folders,                                                          
2283                  ArrayList<Runnable> deferredBindRunnables) {                                                      
2284                                                                                                                    
2285              final boolean postOnMainThread = (deferredBindRunnables != null);                                     
2286                                                                                                                    
2287              // Bind the workspace items                                                                           
2288              int N = workspaceItems.size();                                                                        
2289              for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                            
2290                  final int start = i;                                                                              
2291                  final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                                 
2292                  final Runnable r = new Runnable() {                                                               
2293                      @Override                                                                                     
2294                      public void run() {                                                                           
2295                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2296                          if (callbacks != null) {                                                                  
2297                              callbacks.bindItems(workspaceItems, start, start+chunkSize,                           
2298                                      false);                                                                       
2299                          }                                                                                         
2300                      }                                                                                             
2301                  };                                                                                                
2302                  if (postOnMainThread) {                                                                           
2303                      deferredBindRunnables.add(r);                                                                 
2304                  } else {                                                                                          
2305                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2306                  }                                                                                                 
2307              }                                                                                                     
2308                                                                                                                    
2309              // Bind the folders                                                                                   
2310              if (!folders.isEmpty()) {                                                                             
2311                  final Runnable r = new Runnable() {                                                               
2312                      public void run() {                                                                           
2313                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2314                          if (callbacks != null) {                                                                  
2315                              callbacks.bindFolders(folders);                                                       
2316                          }                                                                                         
2317                      }                                                                                             
2318                  };                                                                                                
2319                  if (postOnMainThread) {                                                                           
2320                      deferredBindRunnables.add(r);                                                                 
2321                  } else {                                                                                          
2322                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2323                  }                                                                                                 
2324              }                                                                                                     
2325                                                                                                                    
2326              // Bind the widgets, one at a time                                                                    
2327              N = appWidgets.size();                                                                                
2328              for (int i = 0; i < N; i++) {                                                                         
2329                  final LauncherAppWidgetInfo widget = appWidgets.get(i);                                           
2330                  final Runnable r = new Runnable() {                                                               
2331                      public void run() {                                                                           
2332                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2333                          if (callbacks != null) {                                                                  
2334                              callbacks.bindAppWidget(widget);                                                      
2335                          }                                                                                         
2336                      }                                                                                             
2337                  };                                                                                                
2338                  if (postOnMainThread) {                                                                           
2339                      deferredBindRunnables.add(r);                                                                 
2340                  } else {                                                                                          
2341                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2342                  }                                                                                                 
2343              }                                                                                                     
2344          }                                                                                                         
2345                                                                                                                    
2346          /**                                                                                                       
2347           * Binds all loaded data to actual views on the main thread.                                              
2348           */                                                                                                       
2349          private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {                        
2350              final long t = SystemClock.uptimeMillis();                                                            
2351              Runnable r;                                                                                           
2352                                                                                                                    
2353              // Don't use these two variables in any of the callback runnables.                                    
2354              // Otherwise we hold a reference to them.                                                             
2355              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2356              if (oldCallbacks == null) {                                                                           
2357                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2358                  Log.w(TAG, "LoaderTask running with no launcher");                                                
2359                  return;                                                                                           
2360              }                                                                                                     
2361                                                                                                                    
2362              // Save a copy of all the bg-thread collections                                                       
2363              ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                                       
2364              ArrayList<LauncherAppWidgetInfo> appWidgets =                                                         
2365                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2366              HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                                  
2367              HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                                   
2368              ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                             
2369              synchronized (sBgLock) {                                                                              
2370                  workspaceItems.addAll(sBgWorkspaceItems);                                                         
2371                  appWidgets.addAll(sBgAppWidgets);                                                                 
2372                  folders.putAll(sBgFolders);                                                                       
2373                  itemsIdMap.putAll(sBgItemsIdMap);                                                                 
2374                  orderedScreenIds.addAll(sBgWorkspaceScreens);                                                     
2375              }                                                                                                     
2376                                                                                                                    
2377              final boolean isLoadingSynchronously =                                                                
2378                      synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                                        
2379              int currScreen = isLoadingSynchronously ? synchronizeBindPage :                                       
2380                  oldCallbacks.getCurrentWorkspaceScreen();                                                         
2381              if (currScreen >= orderedScreenIds.size()) {                                                          
2382                  // There may be no workspace screens (just hotseat items and an empty page).                      
2383                  currScreen = PagedView.INVALID_RESTORE_PAGE;                                                      
2384              }                                                                                                     
2385              final int currentScreen = currScreen;                                                                 
2386              final long currentScreenId = currentScreen < 0                                                        
2387                      ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                                    
2388                                                                                                                    
2389              // Load all the items that are on the current page first (and in the process, unbind                  
2390              // all the existing workspace items before we call startBinding() below.                              
2391              unbindWorkspaceItemsOnMainThread();                                                                   
2392                                                                                                                    
2393              // Separate the items that are on the current screen, and all the other remaining items               
2394              ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                                
2395              ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                                  
2396              ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                                  
2397                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2398              ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                                    
2399                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2400              HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                           
2401              HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                             
2402                                                                                                                    
2403              filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,                   
2404                      otherWorkspaceItems);                                                                         
2405              filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                               
2406                      otherAppWidgets);                                                                             
2407              filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                            
2408                      otherFolders);                                                                                
2409              sortWorkspaceItemsSpatially(currentWorkspaceItems);                                                   
2410              sortWorkspaceItemsSpatially(otherWorkspaceItems);                                                     
2411                                                                                                                    
2412              // Tell the workspace that we're about to start binding items                                         
2413              r = new Runnable() {                                                                                  
2414                  public void run() {                                                                               
2415                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2416                      if (callbacks != null) {                                                                      
2417                          callbacks.startBinding();                                                                 
2418                      }                                                                                             
2419                  }                                                                                                 
2420              };                                                                                                    
2421              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2422                                                                                                                    
2423              bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                                 
2424                                                                                                                    
2425              // Load items on the current page                                                                     
2426              bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                            
2427                      currentFolders, null);                                                                        
2428              if (isLoadingSynchronously) {                                                                         
2429                  r = new Runnable() {                                                                              
2430                      public void run() {                                                                           
2431                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2432                          if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {               
2433                              callbacks.onPageBoundSynchronously(currentScreen);                                    
2434                          }                                                                                         
2435                      }                                                                                             
2436                  };                                                                                                
2437                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2438              }                                                                                                     
2439                                                                                                                    
2440              // Load all the remaining pages (if we are loading synchronously, we want to defer this               
2441              // work until after the first render)                                                                 
2442              mDeferredBindRunnables.clear();                                                                       
2443              bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,                  
2444                      (isLoadingSynchronously ? mDeferredBindRunnables : null));                                    
2445                                                                                                                    
2446              // Tell the workspace that we're done binding items                                                   
2447              r = new Runnable() {                                                                                  
2448                  public void run() {                                                                               
2449                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2450                      if (callbacks != null) {                                                                      
2451                          callbacks.finishBindingItems(isUpgradePath);                                              
2452                      }                                                                                             
2453                                                                                                                    
2454                      // If we're profiling, ensure this is the last thing in the queue.                            
2455                      if (DEBUG_LOADERS) {                                                                          
2456                          Log.d(TAG, "bound workspace in "                                                          
2457                              + (SystemClock.uptimeMillis()-t) + "ms");                                             
2458                      }                                                                                             
2459                                                                                                                    
2460                      mIsLoadingAndBindingWorkspace = false;                                                        
2461                  }                                                                                                 
2462              };                                                                                                    
2463              if (isLoadingSynchronously) {                                                                         
2464                  mDeferredBindRunnables.add(r);                                                                    
2465              } else {                                                                                              
2466                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2467              }                                                                                                     
2468          }                                                                                                         
2469                                                                                                                    
2470          private void loadAndBindAllApps() {                                                                       
2471              if (DEBUG_LOADERS) {                                                                                  
2472                  Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                                
2473              }                                                                                                     
2474              if (!mAllAppsLoaded) {                                                                                
2475                  loadAllApps();                                                                                    
2476                  synchronized (LoaderTask.this) {                                                                  
2477                      if (mStopped) {                                                                               
2478                          return;                                                                                   
2479                      }                                                                                             
2480                      mAllAppsLoaded = true;                                                                        
2481                  }                                                                                                 
2482              } else {                                                                                              
2483                  onlyBindAllApps();                                                                                
2484              }                                                                                                     
2485          }                                                                                                         
2486                                                                                                                    
2487          private void onlyBindAllApps() {                                                                          
2488              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2489              if (oldCallbacks == null) {                                                                           
2490                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2491                  Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                              
2492                  return;                                                                                           
2493              }                                                                                                     
2494                                                                                                                    
2495              // shallow copy                                                                                       
2496              @SuppressWarnings("unchecked")                                                                        
2497              final ArrayList<AppInfo> list                                                                         
2498                      = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                           
2499              Runnable r = new Runnable() {                                                                         
2500                  public void run() {                                                                               
2501                      final long t = SystemClock.uptimeMillis();                                                    
2502                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2503                      if (callbacks != null) {                                                                      
2504                          callbacks.bindAllApplications(list);                                                      
2505                      }                                                                                             
2506                      if (DEBUG_LOADERS) {                                                                          
2507                          Log.d(TAG, "bound all " + list.size() + " apps from cache in "                            
2508                                  + (SystemClock.uptimeMillis()-t) + "ms");                                         
2509                      }                                                                                             
2510                  }                                                                                                 
2511              };                                                                                                    
2512              boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());                    
2513              if (isRunningOnMainThread) {                                                                          
2514                  r.run();                                                                                          
2515              } else {                                                                                              
2516                  mHandler.post(r);                                                                                 
2517              }                                                                                                     
2518          }                                                                                                         
2519                                                                                                                    
2520          private void loadAllApps() {                                                                              
2521              final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
2522                                                                                                                    
2523              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2524              if (oldCallbacks == null) {                                                                           
2525                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2526                  Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                                  
2527                  return;                                                                                           
2528              }                                                                                                     
2529                                                                                                                    
2530              final PackageManager packageManager = mContext.getPackageManager();                                   
2531              final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                                       
2532              mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                     
2533                                                                                                                    
2534              // Clear the list of apps                                                                             
2535              mBgAllAppsList.clear();                                                                               
2536                                                                                                                    
2537              // Query for the set of apps                                                                          
2538              final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                  
2539              List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);                         
2540              if (DEBUG_LOADERS) {                                                                                  
2541                  Log.d(TAG, "queryIntentActivities took "                                                          
2542                          + (SystemClock.uptimeMillis()-qiaTime) + "ms");                                           
2543                  Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");                                 
2544              }                                                                                                     
2545              // Fail if we don't have any apps                                                                     
2546              if (apps == null || apps.isEmpty()) {                                                                 
2547                  return;                                                                                           
2548              }                                                                                                     
2549              // Sort the applications by name                                                                      
2550              final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
2551              Collections.sort(apps,                                                                                
2552                      new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));                       
2553              if (DEBUG_LOADERS) {                                                                                  
2554                  Log.d(TAG, "sort took "                                                                           
2555                          + (SystemClock.uptimeMillis()-sortTime) + "ms");                                          
2556              }                                                                                                     
2557                                                                                                                    
2558              // Create the ApplicationInfos                                                                        
2559              for (int i = 0; i < apps.size(); i++) {                                                               
2560                  ResolveInfo app = apps.get(i);                                                                    
2561                  // This builds the icon bitmaps.                                                                  
2562                  mBgAllAppsList.add(new AppInfo(packageManager, app,                                               
2563                          mIconCache, mLabelCache));                                                                
2564              }                                                                                                     
2565                                                                                                                    
2566              // Huh? Shouldn't this be inside the Runnable below?                                                  
2567              final ArrayList<AppInfo> added = mBgAllAppsList.added;                                                
2568              mBgAllAppsList.added = new ArrayList<AppInfo>();                                                      
2569                                                                                                                    
2570              // Post callback on main thread                                                                       
2571              mHandler.post(new Runnable() {                                                                        
2572                  public void run() {                                                                               
2573                      final long bindTime = SystemClock.uptimeMillis();                                             
2574                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2575                      if (callbacks != null) {                                                                      
2576                          callbacks.bindAllApplications(added);                                                     
2577                          if (DEBUG_LOADERS) {                                                                      
2578                              Log.d(TAG, "bound " + added.size() + " apps in "                                      
2579                                  + (SystemClock.uptimeMillis() - bindTime) + "ms");                                
2580                          }                                                                                         
2581                      } else {                                                                                      
2582                          Log.i(TAG, "not binding apps: no Launcher activity");                                     
2583                      }                                                                                             
2584                  }                                                                                                 
2585              });                                                                                                   
2586                                                                                                                    
2587              if (DEBUG_LOADERS) {                                                                                  
2588                  Log.d(TAG, "Icons processed in "                                                                  
2589                          + (SystemClock.uptimeMillis() - loadTime) + "ms");                                        
2590              }                                                                                                     
2591          }                                                                                                         
2592                                                                                                                    
2593          public void dumpState() {                                                                                 
2594              synchronized (sBgLock) {                                                                              
2595                  Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                                   
2596                  Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                           
2597                  Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                                   
2598                  Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);                   
2599                  Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                            
2600              }                                                                                                     
2601          }                                                                                                         
2602      }                                                                                                             
2603                                                                                                                    
2604      void enqueuePackageUpdated(PackageUpdatedTask task) {                                                         
2605          sWorker.post(task);                                                                                       
2606      }                                                                                                             
2607                                                                                                                    
2608      private class PackageUpdatedTask implements Runnable {                                                        
2609          int mOp;                                                                                                  
2610          String[] mPackages;                                                                                       
2611                                                                                                                    
2612          public static final int OP_NONE = 0;                                                                      
2613          public static final int OP_ADD = 1;                                                                       
2614          public static final int OP_UPDATE = 2;                                                                    
2615          public static final int OP_REMOVE = 3; // uninstlled                                                      
2616          public static final int OP_UNAVAILABLE = 4; // external media unmounted                                   
2617                                                                                                                    
2618                                                                                                                    
2619          public PackageUpdatedTask(int op, String[] packages) {                                                    
2620              mOp = op;                                                                                             
2621              mPackages = packages;                                                                                 
2622          }                                                                                                         
2623                                                                                                                    
2624          public void run() {                                                                                       
2625              final Context context = mApp.getContext();                                                            
2626                                                                                                                    
2627              final String[] packages = mPackages;                                                                  
2628              final int N = packages.length;                                                                        
2629              switch (mOp) {                                                                                        
2630                  case OP_ADD:                                                                                      
2631                      for (int i=0; i<N; i++) {                                                                     
2632                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                  
2633                          mBgAllAppsList.addPackage(context, packages[i]);                                          
2634                      }                                                                                             
2635                      break;                                                                                        
2636                  case OP_UPDATE:                                                                                   
2637                      for (int i=0; i<N; i++) {                                                                     
2638                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);               
2639                          mBgAllAppsList.updatePackage(context, packages[i]);                                       
2640                          WidgetPreviewLoader.removePackageFromDb(                                                  
2641                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
2642                      }                                                                                             
2643                      break;                                                                                        
2644                  case OP_REMOVE:                                                                                   
2645                  case OP_UNAVAILABLE:                                                                              
2646                      for (int i=0; i<N; i++) {                                                                     
2647                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
2648                          mBgAllAppsList.removePackage(packages[i]);                                                
2649                          WidgetPreviewLoader.removePackageFromDb(                                                  
2650                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
2651                      }                                                                                             
2652                      break;                                                                                        
2653              }                                                                                                     
2654                                                                                                                    
2655              ArrayList<AppInfo> added = null;                                                                      
2656              ArrayList<AppInfo> modified = null;                                                                   
2657              final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                                      
2658                                                                                                                    
2659              if (mBgAllAppsList.added.size() > 0) {                                                                
2660                  added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                             
2661                  mBgAllAppsList.added.clear();                                                                     
2662              }                                                                                                     
2663              if (mBgAllAppsList.modified.size() > 0) {                                                             
2664                  modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                                       
2665                  mBgAllAppsList.modified.clear();                                                                  
2666              }                                                                                                     
2667              if (mBgAllAppsList.removed.size() > 0) {                                                              
2668                  removedApps.addAll(mBgAllAppsList.removed);                                                       
2669                  mBgAllAppsList.removed.clear();                                                                   
2670              }                                                                                                     
2671                                                                                                                    
2672              final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                             
2673              if (callbacks == null) {                                                                              
2674                  Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");                   
2675                  return;                                                                                           
2676              }                                                                                                     
2677                                                                                                                    
2678              if (added != null) {                                                                                  
2679                  // Ensure that we add all the workspace applications to the db                                    
2680 -                if (LauncherAppState.isDisableAllApps()) {                                                        
2681 +                Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                      
2682 +                if (!LauncherAppState.isDisableAllApps()) {                                                       
2683 +                    addAndBindAddedApps(context, new ArrayList<ItemInfo>(), cb, added);                           
2684 +                } else {                                                                                          
2685                      final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);                        
2686 -                    addAndBindAddedWorkspaceApps(context, addedInfos);                                            
2687 -                } else {                                                                                          
2688 -                    addAppsToAllApps(context, added);                                                             
2689 -                }                                                                                                 
2690 -            }                                                                                                     
2691 -                                                                                                                  
2692 +                    addAndBindAddedApps(context, addedInfos, cb, added);                                          
2693 +                }                                                                                                 
2694 +            }                                                                                                     
2695              if (modified != null) {                                                                               
2696                  final ArrayList<AppInfo> modifiedFinal = modified;                                                
2697                                                                                                                    
2698                  // Update the launcher db to reflect the changes                                                  
2699                  for (AppInfo a : modifiedFinal) {                                                                 
2700                      ArrayList<ItemInfo> infos =                                                                   
2701                              getItemInfoForComponentName(a.componentName);                                         
2702                      for (ItemInfo i : infos) {                                                                    
2703                          if (isShortcutInfoUpdateable(i)) {                                                        
2704                              ShortcutInfo info = (ShortcutInfo) i;                                                 
2705                              info.title = a.title.toString();                                                      
2706                              updateItemInDatabase(context, info);                                                  
2707                          }                                                                                         
2708                      }                                                                                             
2709                  }                                                                                                 
2710                                                                                                                    
2711                  mHandler.post(new Runnable() {                                                                    
2712                      public void run() {                                                                           
2713                          Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                              
2714                          if (callbacks == cb && cb != null) {                                                      
2715                              callbacks.bindAppsUpdated(modifiedFinal);                                             
2716                          }                                                                                         
2717                      }                                                                                             
2718                  });                                                                                               
2719              }                                                                                                     
2720                                                                                                                    
2721              final ArrayList<String> removedPackageNames =                                                         
2722                      new ArrayList<String>();                                                                      
2723              if (mOp == OP_REMOVE) {                                                                               
2724                  // Mark all packages in the broadcast to be removed                                               
2725                  removedPackageNames.addAll(Arrays.asList(packages));                                              
2726              } else if (mOp == OP_UPDATE) {                                                                        
2727                  // Mark disabled packages in the broadcast to be removed                                          
2728                  final PackageManager pm = context.getPackageManager();                                            
2729                  for (int i=0; i<N; i++) {                                                                         
2730                      if (isPackageDisabled(pm, packages[i])) {                                                     
2731                          removedPackageNames.add(packages[i]);                                                     
2732                      }                                                                                             
2733                  }                                                                                                 
2734              }                                                                                                     
2735              // Remove all the components associated with this package                                             
2736              for (String pn : removedPackageNames) {                                                               
2737                  ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);                                        
2738                  for (ItemInfo i : infos) {                                                                        
2739                      deleteItemFromDatabase(context, i);                                                           
2740                  }                                                                                                 
2741              }                                                                                                     
2742              // Remove all the specific components                                                                 
2743              for (AppInfo a : removedApps) {                                                                       
2744                  ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);                         
2745                  for (ItemInfo i : infos) {                                                                        
2746                      deleteItemFromDatabase(context, i);                                                           
2747                  }                                                                                                 
2748              }                                                                                                     
2749              if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                                       
2750                  // Remove any queued items from the install queue                                                 
2751                  String spKey = LauncherAppState.getSharedPreferencesKey();                                        
2752                  SharedPreferences sp =                                                                            
2753                          context.getSharedPreferences(spKey, Context.MODE_PRIVATE);                                
2754                  InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames);                          
2755                  // Call the components-removed callback                                                           
2756                  mHandler.post(new Runnable() {                                                                    
2757                      public void run() {                                                                           
2758                          Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                              
2759                          if (callbacks == cb && cb != null) {                                                      
2760                              callbacks.bindComponentsRemoved(removedPackageNames, removedApps);                    
2761                          }                                                                                         
2762                      }                                                                                             
2763                  });                                                                                               
2764              }                                                                                                     
2765                                                                                                                    
2766              final ArrayList<Object> widgetsAndShortcuts =                                                         
2767                  getSortedWidgetsAndShortcuts(context);                                                            
2768              mHandler.post(new Runnable() {                                                                        
2769                  @Override                                                                                         
2770                  public void run() {                                                                               
2771                      Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                  
2772                      if (callbacks == cb && cb != null) {                                                          
2773                          callbacks.bindPackagesUpdated(widgetsAndShortcuts);                                       
2774                      }                                                                                             
2775                  }                                                                                                 
2776              });                                                                                                   
2777                                                                                                                    
2778              // Write all the logs to disk                                                                         
2779              mHandler.post(new Runnable() {                                                                        
2780                  public void run() {                                                                               
2781                      Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                  
2782                      if (callbacks == cb && cb != null) {                                                          
2783                          callbacks.dumpLogsToLocalData();                                                          
2784                      }                                                                                             
2785                  }                                                                                                 
2786              });                                                                                                   
2787          }                                                                                                         
2788      }                                                                                                             
2789                                                                                                                    
2790      // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                              
2791      public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                               
2792          PackageManager packageManager = context.getPackageManager();                                              
2793          final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                                    
2794          widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders());                
2795          Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                                       
2796          widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));                     
2797          Collections.sort(widgetsAndShortcuts,                                                                     
2798              new LauncherModel.WidgetAndShortcutNameComparator(packageManager));                                   
2799          return widgetsAndShortcuts;                                                                               
2800      }                                                                                                             
2801                                                                                                                    
2802      private static boolean isPackageDisabled(PackageManager pm, String packageName) {                             
2803          try {                                                                                                     
2804              PackageInfo pi = pm.getPackageInfo(packageName, 0);                                                   
2805              return !pi.applicationInfo.enabled;                                                                   
2806          } catch (NameNotFoundException e) {                                                                       
2807              // Fall through                                                                                       
2808          }                                                                                                         
2809          return false;                                                                                             
2810      }                                                                                                             
2811                                                                                                                    
2812      public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) {                          
2813          if (cn == null) {                                                                                         
2814              return false;                                                                                         
2815          }                                                                                                         
2816          if (isPackageDisabled(pm, cn.getPackageName())) {                                                         
2817              return false;                                                                                         
2818          }                                                                                                         
2819                                                                                                                    
2820          try {                                                                                                     
2821              // Check the activity                                                                                 
2822              PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0);                                           
2823              return (pm.getActivityInfo(cn, 0) != null);                                                           
2824          } catch (NameNotFoundException e) {                                                                       
2825              return false;                                                                                         
2826          }                                                                                                         
2827      }                                                                                                             
2828                                                                                                                    
2829      /**                                                                                                           
2830       * Make an ShortcutInfo object for a restored application or shortcut item that points                        
2831       * to a package that is not yet installed on the system.                                                      
2832       */                                                                                                           
2833      public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex) {                                      

2834          final ShortcutInfo info = new ShortcutInfo();                                                             
2835          info.usingFallbackIcon = true;                                                                            
2836          info.setIcon(getFallbackIcon());                                                                          
2837          if (cursor != null) {                                                                                     
2838              info.title =  cursor.getString(titleIndex);                                                           
2839          } else {                                                                                                  
2840              info.title = "";                                                                                      
2841          }                                                                                                         
2842          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            

2843          return info;                                                                                              
2844      }                                                                                                             
2845                                                                                                                    
2846      /**                                                                                                           
2847       * Make an Intent object for a restored application or shortcut item that points                              
2848       * to the market page for the item.                                                                           
2849       */                                                                                                           
2850      private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                              

2851          ComponentName componentName = intent.getComponent();                                                      
2852          Intent marketIntent = new Intent(Intent.ACTION_VIEW);                                                     
2853          Uri marketUri = new Uri.Builder()                                                                         
2854                  .scheme("market")                                                                                 
2855                  .authority("details")                                                                             
2856                  .appendQueryParameter("id", componentName.getPackageName())                                       
2857                  .build();                                                                                         
2858          Log.d(TAG, "manufactured intent uri: " + marketUri.toString());                                           

2859          marketIntent.setData(marketUri);                                                                          
2860          return marketIntent;                                                                                      
2861      }                                                                                                             
2862                                                                                                                    
2863      /**                                                                                                           
2864       * This is called from the code that adds shortcuts from the intent receiver.  This                           
2865       * doesn't have a Cursor, but                                                                                 
2866       */                                                                                                           
2867      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {                 
2868          return getShortcutInfo(manager, intent, context, null, -1, -1, null);                                     
2869      }                                                                                                             
2870                                                                                                                    
2871      /**                                                                                                           
2872       * Make an ShortcutInfo object for a shortcut that is an application.                                         
2873       *                                                                                                            
2874       * If c is not null, then it will be used to fill in missing data like the title and icon.                    
2875       */                                                                                                           
2876      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,                   
2877              Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {                  
2878          ComponentName componentName = intent.getComponent();                                                      
2879          final ShortcutInfo info = new ShortcutInfo();                                                             
2880          if (componentName != null && !isValidPackageComponent(manager, componentName)) {                          
2881              Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName);                             
2882              return null;                                                                                          
2883          } else {                                                                                                  
2884              try {                                                                                                 
2885                  PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);                       
2886                  info.initFlagsAndFirstInstallTime(pi);                                                            
2887              } catch (NameNotFoundException e) {                                                                   
2888                  Log.d(TAG, "getPackInfo failed for package " +                                                    
2889                          componentName.getPackageName());                                                          
2890              }                                                                                                     
2891          }                                                                                                         
2892                                                                                                                    
2893          // TODO: See if the PackageManager knows about this case.  If it doesn't                                  
2894          // then return null & delete this.                                                                        
2895                                                                                                                    
2896          // the resource -- This may implicitly give us back the fallback icon,                                    
2897          // but don't worry about that.  All we're doing with usingFallbackIcon is                                 
2898          // to avoid saving lots of copies of that in the database, and most apps                                  
2899          // have icons anyway.                                                                                     
2900                                                                                                                    
2901          // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and               
2902          // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info              
2903          // via resolveActivity().                                                                                 
2904          Bitmap icon = null;                                                                                       
2905          ResolveInfo resolveInfo = null;                                                                           
2906          ComponentName oldComponent = intent.getComponent();                                                       
2907          Intent newIntent = new Intent(intent.getAction(), null);                                                  
2908          newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                          
2909          newIntent.setPackage(oldComponent.getPackageName());                                                      
2910          List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);                                    
2911          for (ResolveInfo i : infos) {                                                                             
2912              ComponentName cn = new ComponentName(i.activityInfo.packageName,                                      
2913                      i.activityInfo.name);                                                                         
2914              if (cn.equals(oldComponent)) {                                                                        
2915                  resolveInfo = i;                                                                                  
2916              }                                                                                                     
2917          }                                                                                                         
2918          if (resolveInfo == null) {                                                                                
2919              resolveInfo = manager.resolveActivity(intent, 0);                                                     
2920          }                                                                                                         
2921          if (resolveInfo != null) {                                                                                
2922              icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);                                    
2923          }                                                                                                         
2924          // the db                                                                                                 
2925          if (icon == null) {                                                                                       
2926              if (c != null) {                                                                                      
2927                  icon = getIconFromCursor(c, iconIndex, context);                                                  
2928              }                                                                                                     
2929          }                                                                                                         
2930          // the fallback icon                                                                                      
2931          if (icon == null) {                                                                                       
2932              icon = getFallbackIcon();                                                                             
2933              info.usingFallbackIcon = true;                                                                        
2934          }                                                                                                         
2935          info.setIcon(icon);                                                                                       
2936                                                                                                                    
2937          // from the resource                                                                                      
2938          if (resolveInfo != null) {                                                                                
2939              ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);                       
2940              if (labelCache != null && labelCache.containsKey(key)) {                                              
2941                  info.title = labelCache.get(key);                                                                 
2942              } else {                                                                                              
2943                  info.title = resolveInfo.activityInfo.loadLabel(manager);                                         
2944                  if (labelCache != null) {                                                                         
2945                      labelCache.put(key, info.title);                                                              
2946                  }                                                                                                 
2947              }                                                                                                     
2948          }                                                                                                         
2949          // from the db                                                                                            
2950          if (info.title == null) {                                                                                 
2951              if (c != null) {                                                                                      
2952                  info.title =  c.getString(titleIndex);                                                            
2953              }                                                                                                     
2954          }                                                                                                         
2955          // fall back to the class name of the activity                                                            
2956          if (info.title == null) {                                                                                 
2957              info.title = componentName.getClassName();                                                            
2958          }                                                                                                         
2959          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                         
2960          return info;                                                                                              
2961      }                                                                                                             
2962                                                                                                                    
2963      static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                                        
2964              ItemInfoFilter f) {                                                                                   
2965          HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                                     
2966          for (ItemInfo i : infos) {                                                                                
2967              if (i instanceof ShortcutInfo) {                                                                      
2968                  ShortcutInfo info = (ShortcutInfo) i;                                                             
2969                  ComponentName cn = info.intent.getComponent();                                                    
2970                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
2971                      filtered.add(info);                                                                           
2972                  }                                                                                                 
2973              } else if (i instanceof FolderInfo) {                                                                 
2974                  FolderInfo info = (FolderInfo) i;                                                                 
2975                  for (ShortcutInfo s : info.contents) {                                                            
2976                      ComponentName cn = s.intent.getComponent();                                                   
2977                      if (cn != null && f.filterItem(info, s, cn)) {                                                
2978                          filtered.add(s);                                                                          
2979                      }                                                                                             
2980                  }                                                                                                 
2981              } else if (i instanceof LauncherAppWidgetInfo) {                                                      
2982                  LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                           
2983                  ComponentName cn = info.providerName;                                                             
2984                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
2985                      filtered.add(info);                                                                           
2986                  }                                                                                                 
2987              }                                                                                                     
2988          }                                                                                                         
2989          return new ArrayList<ItemInfo>(filtered);                                                                 
2990      }                                                                                                             
2991                                                                                                                    
2992      private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {                                      
2993          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
2994              @Override                                                                                             
2995              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
2996                  return cn.getPackageName().equals(pn);                                                            
2997              }                                                                                                     
2998          };                                                                                                        
2999          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
3000      }                                                                                                             
3001                                                                                                                    
3002      private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {                          
3003          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
3004              @Override                                                                                             
3005              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
3006                  return cn.equals(cname);                                                                          
3007              }                                                                                                     
3008          };                                                                                                        
3009          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
3010      }                                                                                                             
3011                                                                                                                    
3012      public static boolean isShortcutInfoUpdateable(ItemInfo i) {                                                  
3013          if (i instanceof ShortcutInfo) {                                                                          
3014              ShortcutInfo info = (ShortcutInfo) i;                                                                 
3015              // We need to check for ACTION_MAIN otherwise getComponent() might                                    
3016              // return null for some shortcuts (for instance, for shortcuts to                                     
3017              // web pages.)                                                                                        
3018              Intent intent = info.intent;                                                                          
3019              ComponentName name = intent.getComponent();                                                           
3020              if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&                              
3021                      Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {                              
3022                  return true;                                                                                      
3023              }                                                                                                     




3024          }                                                                                                         
3025          return false;                                                                                             
3026      }                                                                                                             
3027                                                                                                                    
3028      /**                                                                                                           
3029       * Make an ShortcutInfo object for a shortcut that isn't an application.                                      
3030       */                                                                                                           
3031      private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                               
3032              int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,                        
3033              int titleIndex) {                                                                                     
3034                                                                                                                    
3035          Bitmap icon = null;                                                                                       
3036          final ShortcutInfo info = new ShortcutInfo();                                                             
3037          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
3038                                                                                                                    
3039          // TODO: If there's an explicit component and we can't install that, delete it.                           
3040                                                                                                                    
3041          info.title = c.getString(titleIndex);                                                                     
3042                                                                                                                    
3043          int iconType = c.getInt(iconTypeIndex);                                                                   
3044          switch (iconType) {                                                                                       
3045          case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                                       
3046              String packageName = c.getString(iconPackageIndex);                                                   
3047              String resourceName = c.getString(iconResourceIndex);                                                 
3048              PackageManager packageManager = context.getPackageManager();                                          
3049              info.customIcon = false;                                                                              
3050              // the resource                                                                                       
3051              try {                                                                                                 
3052                  Resources resources = packageManager.getResourcesForApplication(packageName);                     
3053                  if (resources != null) {                                                                          
3054                      final int id = resources.getIdentifier(resourceName, null, null);                             
3055                      icon = Utilities.createIconBitmap(                                                            
3056                              mIconCache.getFullResIcon(resources, id), context);                                   
3057                  }                                                                                                 
3058              } catch (Exception e) {                                                                               
3059                  // drop this.  we have other places to look for icons                                             
3060              }                                                                                                     
3061              // the db                                                                                             
3062              if (icon == null) {                                                                                   
3063                  icon = getIconFromCursor(c, iconIndex, context);                                                  
3064              }                                                                                                     
3065              // the fallback icon                                                                                  
3066              if (icon == null) {                                                                                   
3067                  icon = getFallbackIcon();                                                                         
3068                  info.usingFallbackIcon = true;                                                                    
3069              }                                                                                                     
3070              break;                                                                                                
3071          case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                         
3072              icon = getIconFromCursor(c, iconIndex, context);                                                      
3073              if (icon == null) {                                                                                   
3074                  icon = getFallbackIcon();                                                                         
3075                  info.customIcon = false;                                                                          
3076                  info.usingFallbackIcon = true;                                                                    
3077              } else {                                                                                              
3078                  info.customIcon = true;                                                                           
3079              }                                                                                                     
3080              break;                                                                                                
3081          default:                                                                                                  
3082              icon = getFallbackIcon();                                                                             
3083              info.usingFallbackIcon = true;                                                                        
3084              info.customIcon = false;                                                                              
3085              break;                                                                                                
3086          }                                                                                                         
3087          info.setIcon(icon);                                                                                       
3088          return info;                                                                                              
3089      }                                                                                                             
3090                                                                                                                    
3091      Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                          
3092          @SuppressWarnings("all") // suppress dead code warning                                                    
3093          final boolean debug = false;                                                                              
3094          if (debug) {                                                                                              
3095              Log.d(TAG, "getIconFromCursor app="                                                                   
3096                      + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));                    
3097          }                                                                                                         
3098          byte[] data = c.getBlob(iconIndex);                                                                       
3099          try {                                                                                                     
3100              return Utilities.createIconBitmap(                                                                    
3101                      BitmapFactory.decodeByteArray(data, 0, data.length), context);                                
3102          } catch (Exception e) {                                                                                   
3103              return null;                                                                                          
3104          }                                                                                                         
3105      }                                                                                                             
3106                                                                                                                    
3107      ShortcutInfo addShortcut(Context context, Intent data, long container, int screen,                            
3108              int cellX, int cellY, boolean notify) {                                                               
3109          final ShortcutInfo info = infoFromShortcutIntent(context, data, null);                                    
3110          if (info == null) {                                                                                       
3111              return null;                                                                                          
3112          }                                                                                                         
3113          addItemToDatabase(context, info, container, screen, cellX, cellY, notify);                                
3114                                                                                                                    
3115          return info;                                                                                              
3116      }                                                                                                             
3117                                                                                                                    
3118      /**                                                                                                           
3119       * Attempts to find an AppWidgetProviderInfo that matches the given component.                                
3120       */                                                                                                           
3121      AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,                                 
3122              ComponentName component) {                                                                            
3123          List<AppWidgetProviderInfo> widgets =                                                                     
3124              AppWidgetManager.getInstance(context).getInstalledProviders();                                        
3125          for (AppWidgetProviderInfo info : widgets) {                                                              
3126              if (info.provider.equals(component)) {                                                                
3127                  return info;                                                                                      
3128              }                                                                                                     
3129          }                                                                                                         
3130          return null;                                                                                              
3131      }                                                                                                             
3132                                                                                                                    
3133      /**                                                                                                           
3134       * Returns a list of all the widgets that can handle configuration with a particular mimeType.                
3135       */                                                                                                           
3136      List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {                 
3137          final PackageManager packageManager = context.getPackageManager();                                        
3138          final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =                                  
3139              new ArrayList<WidgetMimeTypeHandlerData>();                                                           
3140                                                                                                                    
3141          final Intent supportsIntent =                                                                             
3142              new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);                                  
3143          supportsIntent.setType(mimeType);                                                                         
3144                                                                                                                    
3145          // Create a set of widget configuration components that we can test against                               
3146          final List<AppWidgetProviderInfo> widgets =                                                               
3147              AppWidgetManager.getInstance(context).getInstalledProviders();                                        
3148          final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =                      
3149              new HashMap<ComponentName, AppWidgetProviderInfo>();                                                  
3150          for (AppWidgetProviderInfo info : widgets) {                                                              
3151              configurationComponentToWidget.put(info.configure, info);                                             
3152          }                                                                                                         
3153                                                                                                                    
3154          // Run through each of the intents that can handle this type of clip data, and cross                      
3155          // reference them with the components that are actual configuration components                            
3156          final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,                 
3157                  PackageManager.MATCH_DEFAULT_ONLY);                                                               
3158          for (ResolveInfo info : activities) {                                                                     
3159              final ActivityInfo activityInfo = info.activityInfo;                                                  
3160              final ComponentName infoComponent = new ComponentName(activityInfo.packageName,                       
3161                      activityInfo.name);                                                                           
3162              if (configurationComponentToWidget.containsKey(infoComponent)) {                                      
3163                  supportedConfigurationActivities.add(                                                             
3164                          new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,                                 
3165                                  configurationComponentToWidget.get(infoComponent)));                              
3166              }                                                                                                     
3167          }                                                                                                         
3168          return supportedConfigurationActivities;                                                                  
3169      }                                                                                                             
3170                                                                                                                    
3171      ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {                      
3172          Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                                    
3173          String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                            
3174          Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                                  
3175                                                                                                                    
3176          if (intent == null) {                                                                                     
3177              // If the intent is null, we can't construct a valid ShortcutInfo, so we return null                  
3178              Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                           
3179              return null;                                                                                          
3180          }                                                                                                         
3181                                                                                                                    
3182          Bitmap icon = null;                                                                                       
3183          boolean customIcon = false;                                                                               
3184          ShortcutIconResource iconResource = null;                                                                 
3185                                                                                                                    
3186          if (bitmap != null && bitmap instanceof Bitmap) {                                                         
3187              icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);                   
3188              customIcon = true;                                                                                    
3189          } else {                                                                                                  
3190              Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);                      
3191              if (extra != null && extra instanceof ShortcutIconResource) {                                         
3192                  try {                                                                                             
3193                      iconResource = (ShortcutIconResource) extra;                                                  
3194                      final PackageManager packageManager = context.getPackageManager();                            
3195                      Resources resources = packageManager.getResourcesForApplication(                              
3196                              iconResource.packageName);                                                            
3197                      final int id = resources.getIdentifier(iconResource.resourceName, null, null);                
3198                      icon = Utilities.createIconBitmap(                                                            
3199                              mIconCache.getFullResIcon(resources, id), context);                                   
3200                  } catch (Exception e) {                                                                           
3201                      Log.w(TAG, "Could not load shortcut icon: " + extra);                                         
3202                  }                                                                                                 
3203              }                                                                                                     
3204          }                                                                                                         
3205                                                                                                                    
3206          final ShortcutInfo info = new ShortcutInfo();                                                             
3207                                                                                                                    
3208          if (icon == null) {                                                                                       
3209              if (fallbackIcon != null) {                                                                           
3210                  icon = fallbackIcon;                                                                              
3211              } else {                                                                                              
3212                  icon = getFallbackIcon();                                                                         
3213                  info.usingFallbackIcon = true;                                                                    
3214              }                                                                                                     
3215          }                                                                                                         
3216          info.setIcon(icon);                                                                                       
3217                                                                                                                    
3218          info.title = name;                                                                                        
3219          info.intent = intent;                                                                                     
3220          info.customIcon = customIcon;                                                                             
3221          info.iconResource = iconResource;                                                                         
3222                                                                                                                    
3223          return info;                                                                                              
3224      }                                                                                                             
3225                                                                                                                    
3226      boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,                      
3227              int iconIndex) {                                                                                      
3228          // If apps can't be on SD, don't even bother.                                                             
3229          if (!mAppsCanBeOnRemoveableStorage) {                                                                     
3230              return false;                                                                                         
3231          }                                                                                                         
3232          // If this icon doesn't have a custom icon, check to see                                                  
3233          // what's stored in the DB, and if it doesn't match what                                                  
3234          // we're going to show, store what we are going to show back                                              
3235          // into the DB.  We do this so when we're loading, if the                                                 
3236          // package manager can't find an icon (for example because                                                
3237          // the app is on SD) then we can use that instead.                                                        
3238          if (!info.customIcon && !info.usingFallbackIcon) {                                                        
3239              cache.put(info, c.getBlob(iconIndex));                                                                
3240              return true;                                                                                          
3241          }                                                                                                         
3242          return false;                                                                                             
3243      }                                                                                                             
3244      void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                                       
3245          boolean needSave = false;                                                                                 
3246          try {                                                                                                     
3247              if (data != null) {                                                                                   
3248                  Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                               
3249                  Bitmap loaded = info.getIcon(mIconCache);                                                         
3250                  needSave = !saved.sameAs(loaded);                                                                 
3251              } else {                                                                                              
3252                  needSave = true;                                                                                  
3253              }                                                                                                     
3254          } catch (Exception e) {                                                                                   
3255              needSave = true;                                                                                      
3256          }                                                                                                         
3257          if (needSave) {                                                                                           
3258              Log.d(TAG, "going to save icon bitmap for info=" + info);                                             
3259              // This is slower than is ideal, but this only happens once                                           
3260              // or when the app is updated with a new icon.                                                        
3261              updateItemInDatabase(context, info);                                                                  
3262          }                                                                                                         
3263      }                                                                                                             
3264                                                                                                                    
3265      /**                                                                                                           
3266       * Return an existing FolderInfo object if we have encountered this ID previously,                            
3267       * or make a new one.                                                                                         
3268       */                                                                                                           
3269      private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {                      
3270          // See if a placeholder was created for us already                                                        
3271          FolderInfo folderInfo = folders.get(id);                                                                  
3272          if (folderInfo == null) {                                                                                 
3273              // No placeholder -- create a new instance                                                            
3274              folderInfo = new FolderInfo();                                                                        
3275              folders.put(id, folderInfo);                                                                          
3276          }                                                                                                         
3277          return folderInfo;                                                                                        
3278      }                                                                                                             
3279                                                                                                                    
3280      public static final Comparator<AppInfo> getAppNameComparator() {                                              
3281          final Collator collator = Collator.getInstance();                                                         
3282          return new Comparator<AppInfo>() {                                                                        
3283              public final int compare(AppInfo a, AppInfo b) {                                                      
3284                  int result = collator.compare(a.title.toString().trim(),                                          
3285                          b.title.toString().trim());                                                               
3286                  if (result == 0) {                                                                                
3287                      result = a.componentName.compareTo(b.componentName);                                          
3288                  }                                                                                                 
3289                  return result;                                                                                    
3290              }                                                                                                     
3291          };                                                                                                        
3292      }                                                                                                             
3293      public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                           
3294              = new Comparator<AppInfo>() {                                                                         
3295          public final int compare(AppInfo a, AppInfo b) {                                                          
3296              if (a.firstInstallTime < b.firstInstallTime) return 1;                                                
3297              if (a.firstInstallTime > b.firstInstallTime) return -1;                                               
3298              return 0;                                                                                             
3299          }                                                                                                         
3300      };                                                                                                            
3301      public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() {                             
3302          final Collator collator = Collator.getInstance();                                                         
3303          return new Comparator<AppWidgetProviderInfo>() {                                                          
3304              public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {                          
3305                  return collator.compare(a.label.toString().trim(), b.label.toString().trim());                    
3306              }                                                                                                     
3307          };                                                                                                        
3308      }                                                                                                             
3309      static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                                      
3310          if (info.activityInfo != null) {                                                                          
3311              return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);                      
3312          } else {                                                                                                  
3313              return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);                        
3314          }                                                                                                         
3315      }                                                                                                             
3316      public static class ShortcutNameComparator implements Comparator<ResolveInfo> {                               
3317          private Collator mCollator;                                                                               
3318          private PackageManager mPackageManager;                                                                   
3319          private HashMap<Object, CharSequence> mLabelCache;                                                        
3320          ShortcutNameComparator(PackageManager pm) {                                                               
3321              mPackageManager = pm;                                                                                 
3322              mLabelCache = new HashMap<Object, CharSequence>();                                                    
3323              mCollator = Collator.getInstance();                                                                   
3324          }                                                                                                         
3325          ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {                     
3326              mPackageManager = pm;                                                                                 
3327              mLabelCache = labelCache;                                                                             
3328              mCollator = Collator.getInstance();                                                                   
3329          }                                                                                                         
3330          public final int compare(ResolveInfo a, ResolveInfo b) {                                                  
3331              CharSequence labelA, labelB;                                                                          
3332              ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);                                
3333              ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);                                
3334              if (mLabelCache.containsKey(keyA)) {                                                                  
3335                  labelA = mLabelCache.get(keyA);                                                                   
3336              } else {                                                                                              
3337                  labelA = a.loadLabel(mPackageManager).toString().trim();                                          
3338                                                                                                                    
3339                  mLabelCache.put(keyA, labelA);                                                                    
3340              }                                                                                                     
3341              if (mLabelCache.containsKey(keyB)) {                                                                  
3342                  labelB = mLabelCache.get(keyB);                                                                   
3343              } else {                                                                                              
3344                  labelB = b.loadLabel(mPackageManager).toString().trim();                                          
3345                                                                                                                    
3346                  mLabelCache.put(keyB, labelB);                                                                    
3347              }                                                                                                     
3348              return mCollator.compare(labelA, labelB);                                                             
3349          }                                                                                                         
3350      };                                                                                                            
3351      public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                           
3352          private Collator mCollator;                                                                               
3353          private PackageManager mPackageManager;                                                                   
3354          private HashMap<Object, String> mLabelCache;                                                              
3355          WidgetAndShortcutNameComparator(PackageManager pm) {                                                      
3356              mPackageManager = pm;                                                                                 
3357              mLabelCache = new HashMap<Object, String>();                                                          
3358              mCollator = Collator.getInstance();                                                                   
3359          }                                                                                                         
3360          public final int compare(Object a, Object b) {                                                            
3361              String labelA, labelB;                                                                                
3362              if (mLabelCache.containsKey(a)) {                                                                     
3363                  labelA = mLabelCache.get(a);                                                                      
3364              } else {                                                                                              
3365                  labelA = (a instanceof AppWidgetProviderInfo) ?                                                   
3366                      ((AppWidgetProviderInfo) a).label :                                                           
3367                      ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                               
3368                  mLabelCache.put(a, labelA);                                                                       
3369              }                                                                                                     
3370              if (mLabelCache.containsKey(b)) {                                                                     
3371                  labelB = mLabelCache.get(b);                                                                      
3372              } else {                                                                                              
3373                  labelB = (b instanceof AppWidgetProviderInfo) ?                                                   
3374                      ((AppWidgetProviderInfo) b).label :                                                           
3375                      ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                               
3376                  mLabelCache.put(b, labelB);                                                                       
3377              }                                                                                                     
3378              return mCollator.compare(labelA, labelB);                                                             
3379          }                                                                                                         
3380      };                                                                                                            
3381                                                                                                                    
3382      public void dumpState() {                                                                                     
3383          Log.d(TAG, "mCallbacks=" + mCallbacks);                                                                   
3384          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                           
3385          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                         
3386          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);                     
3387          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);                   
3388          if (mLoaderTask != null) {                                                                                
3389              mLoaderTask.dumpState();                                                                              
3390          } else {                                                                                                  
3391              Log.d(TAG, "mLoaderTask=null");                                                                       
3392          }                                                                                                         
3393      }                                                                                                             
3394  }                                                                                                                 
   1  /*                                                                                                                
   2   * Copyright (C) 2008 The Android Open Source Project                                                             
   3   *                                                                                                                
   4   * Licensed under the Apache License, Version 2.0 (the "License");                                                
   5   * you may not use this file except in compliance with the License.                                               
   6   * You may obtain a copy of the License at                                                                        
   7   *                                                                                                                
   8   *      http://www.apache.org/licenses/LICENSE-2.0                                                                
   9   *                                                                                                                
  10   * Unless required by applicable law or agreed to in writing, software                                            
  11   * distributed under the License is distributed on an "AS IS" BASIS,                                              
  12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                       
  13   * See the License for the specific language governing permissions and                                            
  14   * limitations under the License.                                                                                 
  15   */                                                                                                               
  16                                                                                                                    
  17  package com.android.launcher3;                                                                                    
  18                                                                                                                    
  19  import android.app.SearchManager;                                                                                 
  20  import android.appwidget.AppWidgetManager;                                                                        
  21  import android.appwidget.AppWidgetProviderInfo;                                                                   
  22  import android.content.*;                                                                                         
  23  import android.content.Intent.ShortcutIconResource;                                                               
  24  import android.content.pm.ActivityInfo;                                                                           
  25  import android.content.pm.PackageInfo;                                                                            
  26  import android.content.pm.PackageManager;                                                                         
  27  import android.content.pm.PackageManager.NameNotFoundException;                                                   
  28  import android.content.pm.ResolveInfo;                                                                            
  29  import android.content.res.Configuration;                                                                         
  30  import android.content.res.Resources;                                                                             
  31  import android.database.Cursor;                                                                                   
  32  import android.graphics.Bitmap;                                                                                   
  33  import android.graphics.BitmapFactory;                                                                            
  34  import android.net.Uri;                                                                                           
  35  import android.os.Environment;                                                                                    
  36  import android.os.Handler;                                                                                        
  37  import android.os.HandlerThread;                                                                                  
  38  import android.os.Parcelable;                                                                                     
  39  import android.os.Process;                                                                                        
  40  import android.os.RemoteException;                                                                                
  41  import android.os.SystemClock;                                                                                    
  42  import android.provider.BaseColumns;                                                                              
  43  import android.text.TextUtils;                                                                                    
  44  import android.util.Log;                                                                                          
  45  import android.util.Pair;                                                                                         
  46                                                                                                                    
  47  import com.android.launcher3.InstallWidgetReceiver.WidgetMimeTypeHandlerData;                                     
  48                                                                                                                    
  49  import java.lang.ref.WeakReference;                                                                               
  50  import java.net.URISyntaxException;                                                                               
  51  import java.text.Collator;                                                                                        
  52  import java.util.ArrayList;                                                                                       
  53  import java.util.Arrays;                                                                                          
  54  import java.util.Collection;                                                                                      
  55  import java.util.Collections;                                                                                     
  56  import java.util.Comparator;                                                                                      
  57  import java.util.HashMap;                                                                                         
  58  import java.util.HashSet;                                                                                         
  59  import java.util.Iterator;                                                                                        
  60  import java.util.List;                                                                                            
  61  import java.util.Set;                                                                                             
  62  import java.util.TreeMap;                                                                                         
  63  import java.util.concurrent.atomic.AtomicBoolean;                                                                 
  64                                                                                                                    
  65  /**                                                                                                               
  66   * Maintains in-memory state of the Launcher. It is expected that there should be only one                        
  67   * LauncherModel object held in a static. Also provide APIs for updating the database state                       
  68   * for the Launcher.                                                                                              
  69   */                                                                                                               
  70  public class LauncherModel extends BroadcastReceiver {                                                            
  71      static final boolean DEBUG_LOADERS = false;                                                                   
  72      static final String TAG = "Launcher.Model";                                                                   
  73                                                                                                                    
  74      // true = use a "More Apps" folder for non-workspace apps on upgrade                                          
  75      // false = strew non-workspace apps across the workspace on upgrade                                           
  76      public static final boolean UPGRADE_USE_MORE_APPS_FOLDER = false;                                             
  77                                                                                                                    
  78      public static final int LOADER_FLAG_NONE = 0;                                                                 
  79      public static final int LOADER_FLAG_CLEAR_WORKSPACE = 1 << 0;                                                 
  80      public static final int LOADER_FLAG_MIGRATE_SHORTCUTS = 1 << 1;                                               
  81                                                                                                                    
  82      private static final int ITEMS_CHUNK = 6; // batch size for the workspace icons                               
  83      private static final long INVALID_SCREEN_ID = -1L;                                                            
  84                                                                                                                    
  85      private final boolean mAppsCanBeOnRemoveableStorage;                                                          
  86      private final boolean mOldContentProviderExists;                                                              
  87                                                                                                                    
  88      private final LauncherAppState mApp;                                                                          
  89      private final Object mLock = new Object();                                                                    
  90      private DeferredHandler mHandler = new DeferredHandler();                                                     
  91      private LoaderTask mLoaderTask;                                                                               
  92      private boolean mIsLoaderTaskRunning;                                                                         
  93      private volatile boolean mFlushingWorkerThread;                                                               
  94                                                                                                                    
  95      // Specific runnable types that are run on the main thread deferred handler, this allows us to                
  96      // clear all queued binding runnables when the Launcher activity is destroyed.                                
  97      private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;                                                     
  98      private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;                                                    
  99                                                                                                                    
 100                                                                                                                    
 101      private static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");                      
 102      static {                                                                                                      
 103          sWorkerThread.start();                                                                                    
 104      }                                                                                                             
 105      private static final Handler sWorker = new Handler(sWorkerThread.getLooper());                                
 106                                                                                                                    
 107      // We start off with everything not loaded.  After that, we assume that                                       
 108      // our monitoring of the package manager provides all updates and we never                                    
 109      // need to do a requery.  These are only ever touched from the loader thread.                                 
 110      private boolean mWorkspaceLoaded;                                                                             
 111      private boolean mAllAppsLoaded;                                                                               
 112                                                                                                                    
 113      // When we are loading pages synchronously, we can't just post the binding of items on the side               
 114      // pages as this delays the rotation process.  Instead, we wait for a callback from the first                 
 115      // draw (in Workspace) to initiate the binding of the remaining side pages.  Any time we start                
 116      // a normal load, we also clear this set of Runnables.                                                        
 117      static final ArrayList<Runnable> mDeferredBindRunnables = new ArrayList<Runnable>();                          
 118                                                                                                                    
 119      private WeakReference<Callbacks> mCallbacks;                                                                  
 120                                                                                                                    
 121      // < only access in worker thread >                                                                           
 122      AllAppsList mBgAllAppsList;                                                                                   
 123                                                                                                                    
 124      // The lock that must be acquired before referencing any static bg data structures.  Unlike                   
 125      // other locks, this one can generally be held long-term because we never expect any of these                 
 126      // static data structures to be referenced outside of the worker thread except on the first                   
 127      // load after configuration change.                                                                           
 128      static final Object sBgLock = new Object();                                                                   
 129                                                                                                                    
 130      // sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by                        
 131      // LauncherModel to their ids                                                                                 
 132      static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();                           
 133                                                                                                                    
 134      // sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts                
 135      //       created by LauncherModel that are directly on the home screen (however, no widgets or                
 136      //       shortcuts within folders).                                                                           
 137      static final ArrayList<ItemInfo> sBgWorkspaceItems = new ArrayList<ItemInfo>();                               
 138                                                                                                                    
 139      // sBgAppWidgets is all LauncherAppWidgetInfo created by LauncherModel. Passed to bindAppWidget()             
 140      static final ArrayList<LauncherAppWidgetInfo> sBgAppWidgets =                                                 
 141          new ArrayList<LauncherAppWidgetInfo>();                                                                   
 142                                                                                                                    
 143      // sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()                            
 144      static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();                          
 145                                                                                                                    
 146      // sBgDbIconCache is the set of ItemInfos that need to have their icons updated in the database               
 147      static final HashMap<Object, byte[]> sBgDbIconCache = new HashMap<Object, byte[]>();                          
 148                                                                                                                    
 149      // sBgWorkspaceScreens is the ordered set of workspace screens.                                               
 150      static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();                                     
 151                                                                                                                    
 152      // </ only access in worker thread >                                                                          
 153                                                                                                                    
 154      private IconCache mIconCache;                                                                                 
 155      private Bitmap mDefaultIcon;                                                                                  
 156                                                                                                                    
 157      protected int mPreviousConfigMcc;                                                                             
 158                                                                                                                    
 159      public interface Callbacks {                                                                                  
 160          public boolean setLoadOnResume();                                                                         
 161          public int getCurrentWorkspaceScreen();                                                                   
 162          public void startBinding();                                                                               
 163          public void bindItems(ArrayList<ItemInfo> shortcuts, int start, int end,                                  
 164                                boolean forceAnimateIcons);                                                         
 165          public void bindScreens(ArrayList<Long> orderedScreenIds);                                                
 166          public void bindAddScreens(ArrayList<Long> orderedScreenIds);                                             
 167          public void bindFolders(HashMap<Long,FolderInfo> folders);                                                
 168          public void finishBindingItems(boolean upgradePath);                                                      
 169          public void bindAppWidget(LauncherAppWidgetInfo info);                                                    
 170          public void bindAllApplications(ArrayList<AppInfo> apps);                                                 
 171          public void bindAppsAdded(ArrayList<Long> newScreens,                                                     
 172                                    ArrayList<ItemInfo> addNotAnimated,                                             
 173                                    ArrayList<ItemInfo> addAnimated,                                                
 174                                    ArrayList<AppInfo> addedApps);                                                  
 175          public void bindAppsUpdated(ArrayList<AppInfo> apps);                                                     
 176          public void bindComponentsRemoved(ArrayList<String> packageNames,                                         
 177                          ArrayList<AppInfo> appInfos);                                                             
 178          public void bindPackagesUpdated(ArrayList<Object> widgetsAndShortcuts);                                   
 179          public void bindSearchablesChanged();                                                                     
 180          public boolean isAllAppsButtonRank(int rank);                                                             
 181          public void onPageBoundSynchronously(int page);                                                           
 182          public void dumpLogsToLocalData();                                                                        
 183      }                                                                                                             
 184                                                                                                                    
 185      public interface ItemInfoFilter {                                                                             
 186          public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn);                              
 187      }                                                                                                             
 188                                                                                                                    
 189      LauncherModel(LauncherAppState app, IconCache iconCache, AppFilter appFilter) {                               
 190          Context context = app.getContext();                                                                       
 191          ContentResolver contentResolver = context.getContentResolver();                                           
 192                                                                                                                    
 193          mAppsCanBeOnRemoveableStorage = Environment.isExternalStorageRemovable();                                 
 194          mOldContentProviderExists = (contentResolver.acquireContentProviderClient(                                
 195                  LauncherSettings.Favorites.OLD_CONTENT_URI) != null);                                             
 196          mApp = app;                                                                                               
 197          mBgAllAppsList = new AllAppsList(iconCache, appFilter);                                                   
 198          mIconCache = iconCache;                                                                                   
 199                                                                                                                    
 200          final Resources res = context.getResources();                                                             
 201          Configuration config = res.getConfiguration();                                                            
 202          mPreviousConfigMcc = config.mcc;                                                                          
 203      }                                                                                                             
 204                                                                                                                    
 205      /** Runs the specified runnable immediately if called from the main thread, otherwise it is                   
 206       * posted on the main thread handler. */                                                                      
 207      private void runOnMainThread(Runnable r) {                                                                    
 208          runOnMainThread(r, 0);                                                                                    
 209      }                                                                                                             
 210      private void runOnMainThread(Runnable r, int type) {                                                          
 211          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 212              // If we are on the worker thread, post onto the main handler                                         
 213              mHandler.post(r);                                                                                     
 214          } else {                                                                                                  
 215              r.run();                                                                                              
 216          }                                                                                                         
 217      }                                                                                                             
 218                                                                                                                    
 219      /** Runs the specified runnable immediately if called from the worker thread, otherwise it is                 
 220       * posted on the worker thread handler. */                                                                    
 221      private static void runOnWorkerThread(Runnable r) {                                                           
 222          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 223              r.run();                                                                                              
 224          } else {                                                                                                  
 225              // If we are not on the worker thread, then post to the worker handler                                
 226              sWorker.post(r);                                                                                      
 227          }                                                                                                         
 228      }                                                                                                             
 229                                                                                                                    
 230      boolean canMigrateFromOldLauncherDb(Launcher launcher) {                                                      
 231          return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ;                                  
 232      }                                                                                                             
 233                                                                                                                    
 234      static boolean findNextAvailableIconSpaceInScreen(ArrayList<ItemInfo> items, int[] xy,                        
 235                                   long screen) {                                                                   
 236          LauncherAppState app = LauncherAppState.getInstance();                                                    
 237          DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                             
 238          final int xCount = (int) grid.numColumns;                                                                 
 239          final int yCount = (int) grid.numRows;                                                                    
 240          boolean[][] occupied = new boolean[xCount][yCount];                                                       
 241                                                                                                                    
 242          int cellX, cellY, spanX, spanY;                                                                           
 243          for (int i = 0; i < items.size(); ++i) {                                                                  
 244              final ItemInfo item = items.get(i);                                                                   
 245              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                                 
 246                  if (item.screenId == screen) {                                                                    
 247                      cellX = item.cellX;                                                                           
 248                      cellY = item.cellY;                                                                           
 249                      spanX = item.spanX;                                                                           
 250                      spanY = item.spanY;                                                                           
 251                      for (int x = cellX; 0 <= x && x < cellX + spanX && x < xCount; x++) {                         
 252                          for (int y = cellY; 0 <= y && y < cellY + spanY && y < yCount; y++) {                     
 253                              occupied[x][y] = true;                                                                
 254                          }                                                                                         
 255                      }                                                                                             
 256                  }                                                                                                 
 257              }                                                                                                     
 258          }                                                                                                         
 259                                                                                                                    
 260          return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied);                                     
 261      }                                                                                                             
 262      static Pair<Long, int[]> findNextAvailableIconSpace(Context context, String name,                             
 263                                                          Intent launchIntent,                                      
 264                                                          int firstScreenIndex,                                     
 265                                                          ArrayList<Long> workspaceScreens) {                       
 266          // Lock on the app so that we don't try and get the items while apps are being added                      
 267          LauncherAppState app = LauncherAppState.getInstance();                                                    
 268          LauncherModel model = app.getModel();                                                                     
 269          boolean found = false;                                                                                    
 270          synchronized (app) {                                                                                      
 271              if (sWorkerThread.getThreadId() != Process.myTid()) {                                                 
 272                  // Flush the LauncherModel worker thread, so that if we just did another                          
 273                  // processInstallShortcut, we give it time for its shortcut to get added to the                   
 274                  // database (getItemsInLocalCoordinates reads the database)                                       
 275                  model.flushWorkerThread();                                                                        
 276              }                                                                                                     
 277              final ArrayList<ItemInfo> items = LauncherModel.getItemsInLocalCoordinates(context);                  
 278                                                                                                                    
 279              // Try adding to the workspace screens incrementally, starting at the default or center               
 280              // screen and alternating between +1, -1, +2, -2, etc. (using ~ ceil(i/2f)*(-1)^(i-1))                
 281              firstScreenIndex = Math.min(firstScreenIndex, workspaceScreens.size());                               
 282              int count = workspaceScreens.size();                                                                  
 283              for (int screen = firstScreenIndex; screen < count && !found; screen++) {                             
 284                  int[] tmpCoordinates = new int[2];                                                                
 285                  if (findNextAvailableIconSpaceInScreen(items, tmpCoordinates,                                     
 286                          workspaceScreens.get(screen))) {                                                          
 287                      // Update the Launcher db                                                                     
 288                      return new Pair<Long, int[]>(workspaceScreens.get(screen), tmpCoordinates);                   
 289                  }                                                                                                 
 290              }                                                                                                     
 291          }                                                                                                         
 292          return null;                                                                                              
 293      }                                                                                                             
 294                                                                                                                    
 295      public void addAppsToAllApps(final Context ctx, final ArrayList<AppInfo> allAppsApps) {                       
 296          final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                                 
 297                                                                                                                    
 298          if (allAppsApps == null) {                                                                                
 299              throw new RuntimeException("allAppsApps must not be null");                                           
 300          }                                                                                                         
 301          if (allAppsApps.isEmpty()) {                                                                              
 302              return;                                                                                               
 303          }                                                                                                         
 304                                                                                                                    
 305 +        final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();                                    
 306 +        Iterator<AppInfo> iter = allAppsApps.iterator();                                                          
 307 +        while (iter.hasNext()) {                                                                                  
 308 +            ItemInfo a = iter.next();                                                                             
 309 +            if (LauncherModel.appWasRestored(ctx, a.getIntent())) {                                               
 310 +                restoredAppsFinal.add((AppInfo) a);                                                               
 311 +            }                                                                                                     
 312 +        }                                                                                                         
 313 +                                                                                                                  
 314          // Process the newly added applications and add them to the database first                                
 315          Runnable r = new Runnable() {                                                                             
 316              public void run() {                                                                                   
 317                  runOnMainThread(new Runnable() {                                                                  
 318                      public void run() {                                                                           
 319                          Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                              
 320                          if (callbacks == cb && cb != null) {                                                      
 321                              callbacks.bindAppsAdded(null, null, null, allAppsApps);                               
 322 +                            if (!restoredAppsFinal.isEmpty()) {                                                   
 323 +                                callbacks.bindAppsUpdated(restoredAppsFinal);                                     
 324 +                            }                                                                                     
 325                          }                                                                                         
 326                      }                                                                                             
 327                  });                                                                                               
 328              }                                                                                                     
 329          };                                                                                                        
 330          runOnWorkerThread(r);                                                                                     
 331      }                                                                                                             
 332                                                                                                                    
 333      public void addAndBindAddedWorkspaceApps(final Context context,                                               
 334              final ArrayList<ItemInfo> workspaceApps) {                                                            
 335          final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                                 
 336                                                                                                                    
 337          if (workspaceApps == null) {                                                                              








 338              throw new RuntimeException("workspaceApps and allAppsApps must not be null");                         
 339          }                                                                                                         
 340          if (workspaceApps.isEmpty()) {                                                                            

 341              return;                                                                                               
 342          }                                                                                                         
 343          // Process the newly added applications and add them to the database first                                
 344          Runnable r = new Runnable() {                                                                             
 345              public void run() {                                                                                   
 346                  final ArrayList<ItemInfo> addedShortcutsFinal = new ArrayList<ItemInfo>();                        
 347                  final ArrayList<Long> addedWorkspaceScreensFinal = new ArrayList<Long>();                         
 348 +                final ArrayList<AppInfo> restoredAppsFinal = new ArrayList<AppInfo>();                            
 349                                                                                                                    
 350                  // Get the list of workspace screens.  We need to append to this list and                         
 351                  // can not use sBgWorkspaceScreens because loadWorkspace() may not have been                      
 352                  // called.                                                                                        
 353                  ArrayList<Long> workspaceScreens = new ArrayList<Long>();                                         
 354                  TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(context);                          
 355                  for (Integer i : orderedScreens.keySet()) {                                                       
 356                      long screenId = orderedScreens.get(i);                                                        
 357                      workspaceScreens.add(screenId);                                                               
 358                  }                                                                                                 
 359                                                                                                                    
 360                  synchronized(sBgLock) {                                                                           
 361                      Iterator<ItemInfo> iter = workspaceApps.iterator();                                           
 362                      while (iter.hasNext()) {                                                                      
 363                          ItemInfo a = iter.next();                                                                 
 364                          final String name = a.title.toString();                                                   
 365                          final Intent launchIntent = a.getIntent();                                                
 366                                                                                                                    
 367                          // Short-circuit this logic if the icon exists somewhere on the workspace                 
 368                          if (LauncherModel.shortcutExists(context, name, launchIntent)) {                          
 369 +                            // Only InstallShortcutReceiver sends us shortcutInfos, ignore them                   
 370 +                            if (a instanceof AppInfo &&                                                           
 371 +                                    LauncherModel.appWasRestored(context, launchIntent)) {                        
 372 +                                restoredAppsFinal.add((AppInfo) a);                                               
 373 +                            }                                                                                     
 374                              continue;                                                                             
 375                          }                                                                                         
 376                                                                                                                    
 377                          // Add this icon to the db, creating a new page if necessary.  If there                   
 378                          // is only the empty page then we just add items to the first page.                       
 379                          // Otherwise, we add them to the next pages.                                              
 380                          int startSearchPageIndex = workspaceScreens.isEmpty() ? 0 : 1;                            
 381                          Pair<Long, int[]> coords = LauncherModel.findNextAvailableIconSpace(context,              
 382                                  name, launchIntent, startSearchPageIndex, workspaceScreens);                      
 383                          if (coords == null) {                                                                     
 384                              LauncherProvider lp = LauncherAppState.getLauncherProvider();                         
 385                                                                                                                    
 386                              // If we can't find a valid position, then just add a new screen.                     
 387                              // This takes time so we need to re-queue the add until the new                       
 388                              // page is added.  Create as many screens as necessary to satisfy                     
 389                              // the startSearchPageIndex.                                                          
 390                              int numPagesToAdd = Math.max(1, startSearchPageIndex + 1 -                            
 391                                      workspaceScreens.size());                                                     
 392                              while (numPagesToAdd > 0) {                                                           
 393                                  long screenId = lp.generateNewScreenId();                                         
 394                                  // Save the screen id for binding in the workspace                                
 395                                  workspaceScreens.add(screenId);                                                   
 396                                  addedWorkspaceScreensFinal.add(screenId);                                         
 397                                  numPagesToAdd--;                                                                  
 398                              }                                                                                     
 399                                                                                                                    
 400                              // Find the coordinate again                                                          
 401                              coords = LauncherModel.findNextAvailableIconSpace(context,                            
 402                                      name, launchIntent, startSearchPageIndex, workspaceScreens);                  
 403                          }                                                                                         
 404                          if (coords == null) {                                                                     
 405                              throw new RuntimeException("Coordinates should not be null");                         
 406                          }                                                                                         
 407                                                                                                                    
 408                          ShortcutInfo shortcutInfo;                                                                
 409                          if (a instanceof ShortcutInfo) {                                                          
 410                              shortcutInfo = (ShortcutInfo) a;                                                      
 411                          } else if (a instanceof AppInfo) {                                                        
 412                              shortcutInfo = ((AppInfo) a).makeShortcut();                                          
 413                          } else {                                                                                  
 414                              throw new RuntimeException("Unexpected info type");                                   
 415                          }                                                                                         
 416                                                                                                                    
 417                          // Add the shortcut to the db                                                             
 418                          addItemToDatabase(context, shortcutInfo,                                                  
 419                                  LauncherSettings.Favorites.CONTAINER_DESKTOP,                                     
 420                                  coords.first, coords.second[0], coords.second[1], false);                         
 421                          // Save the ShortcutInfo for binding in the workspace                                     
 422                          addedShortcutsFinal.add(shortcutInfo);                                                    
 423                      }                                                                                             
 424                  }                                                                                                 
 425                                                                                                                    
 426                  // Update the workspace screens                                                                   
 427                  updateWorkspaceScreenOrder(context, workspaceScreens);                                            
 428                                                                                                                    
 429                  if (!addedShortcutsFinal.isEmpty()) {                                                             

 430                      runOnMainThread(new Runnable() {                                                              
 431                          public void run() {                                                                       
 432                              Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                          
 433                              if (callbacks == cb && cb != null) {                                                  
 434                                  final ArrayList<ItemInfo> addAnimated = new ArrayList<ItemInfo>();                
 435                                  final ArrayList<ItemInfo> addNotAnimated = new ArrayList<ItemInfo>();             
 436                                  if (!addedShortcutsFinal.isEmpty()) {                                             
 437                                      ItemInfo info = addedShortcutsFinal.get(addedShortcutsFinal.size() - 1);      
 438                                      long lastScreenId = info.screenId;                                            
 439                                      for (ItemInfo i : addedShortcutsFinal) {                                      
 440                                          if (i.screenId == lastScreenId) {                                         
 441                                              addAnimated.add(i);                                                   
 442                                          } else {                                                                  
 443                                              addNotAnimated.add(i);                                                
 444                                          }                                                                         
 445                                      }                                                                             
 446                                  }                                                                                 
 447                                  callbacks.bindAppsAdded(addedWorkspaceScreensFinal,                               
 448                                          addNotAnimated, addAnimated, null);                                       
 449 +                                if (!restoredAppsFinal.isEmpty()) {                                               
 450 +                                    callbacks.bindAppsUpdated(restoredAppsFinal);                                 
 451 +                                }                                                                                 
 452                              }                                                                                     
 453                          }                                                                                         
 454                      });                                                                                           
 455                  }                                                                                                 
 456              }                                                                                                     
 457          };                                                                                                        
 458          runOnWorkerThread(r);                                                                                     
 459      }                                                                                                             
 460                                                                                                                    
 461      public Bitmap getFallbackIcon() {                                                                             
 462          if (mDefaultIcon == null) {                                                                               
 463              final Context context = LauncherAppState.getInstance().getContext();                                  
 464              mDefaultIcon = Utilities.createIconBitmap(                                                            
 465                      mIconCache.getFullResDefaultActivityIcon(), context);                                         
 466          }                                                                                                         
 467          return Bitmap.createBitmap(mDefaultIcon);                                                                 
 468      }                                                                                                             
 469                                                                                                                    
 470      public void unbindItemInfosAndClearQueuedBindRunnables() {                                                    
 471          if (sWorkerThread.getThreadId() == Process.myTid()) {                                                     
 472              throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +              
 473                      "main thread");                                                                               
 474          }                                                                                                         
 475                                                                                                                    
 476          // Clear any deferred bind runnables                                                                      
 477          mDeferredBindRunnables.clear();                                                                           
 478          // Remove any queued bind runnables                                                                       
 479          mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);                                          
 480          // Unbind all the workspace items                                                                         
 481          unbindWorkspaceItemsOnMainThread();                                                                       
 482      }                                                                                                             
 483                                                                                                                    
 484      /** Unbinds all the sBgWorkspaceItems and sBgAppWidgets on the main thread */                                 
 485      void unbindWorkspaceItemsOnMainThread() {                                                                     
 486          // Ensure that we don't use the same workspace items data structure on the main thread                    
 487          // by making a copy of workspace items first.                                                             
 488          final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();                                  
 489          final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();                                      
 490          synchronized (sBgLock) {                                                                                  
 491              tmpWorkspaceItems.addAll(sBgWorkspaceItems);                                                          
 492              tmpAppWidgets.addAll(sBgAppWidgets);                                                                  
 493          }                                                                                                         
 494          Runnable r = new Runnable() {                                                                             
 495                  @Override                                                                                         
 496                  public void run() {                                                                               
 497                     for (ItemInfo item : tmpWorkspaceItems) {                                                      
 498                         item.unbind();                                                                             
 499                     }                                                                                              
 500                     for (ItemInfo item : tmpAppWidgets) {                                                          
 501                         item.unbind();                                                                             
 502                     }                                                                                              
 503                  }                                                                                                 
 504              };                                                                                                    
 505          runOnMainThread(r);                                                                                       
 506      }                                                                                                             
 507                                                                                                                    
 508      /**                                                                                                           
 509       * Adds an item to the DB if it was not created previously, or move it to a new                               
 510       * <container, screen, cellX, cellY>                                                                          
 511       */                                                                                                           
 512      static void addOrMoveItemInDatabase(Context context, ItemInfo item, long container,                           
 513              long screenId, int cellX, int cellY) {                                                                
 514          if (item.container == ItemInfo.NO_ID) {                                                                   
 515              // From all apps                                                                                      
 516              addItemToDatabase(context, item, container, screenId, cellX, cellY, false);                           
 517          } else {                                                                                                  
 518              // From somewhere else                                                                                
 519              moveItemInDatabase(context, item, container, screenId, cellX, cellY);                                 
 520          }                                                                                                         
 521      }                                                                                                             
 522                                                                                                                    
 523      static void checkItemInfoLocked(                                                                              
 524              final long itemId, final ItemInfo item, StackTraceElement[] stackTrace) {                             
 525          ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                           
 526          if (modelItem != null && item != modelItem) {                                                             
 527              // check all the data is consistent                                                                   
 528              if (modelItem instanceof ShortcutInfo && item instanceof ShortcutInfo) {                              
 529                  ShortcutInfo modelShortcut = (ShortcutInfo) modelItem;                                            
 530                  ShortcutInfo shortcut = (ShortcutInfo) item;                                                      
 531                  if (modelShortcut.title.toString().equals(shortcut.title.toString()) &&                           
 532                          modelShortcut.intent.filterEquals(shortcut.intent) &&                                     
 533                          modelShortcut.id == shortcut.id &&                                                        
 534                          modelShortcut.itemType == shortcut.itemType &&                                            
 535                          modelShortcut.container == shortcut.container &&                                          
 536                          modelShortcut.screenId == shortcut.screenId &&                                            
 537                          modelShortcut.cellX == shortcut.cellX &&                                                  
 538                          modelShortcut.cellY == shortcut.cellY &&                                                  
 539                          modelShortcut.spanX == shortcut.spanX &&                                                  
 540                          modelShortcut.spanY == shortcut.spanY &&                                                  
 541                          ((modelShortcut.dropPos == null && shortcut.dropPos == null) ||                           
 542                          (modelShortcut.dropPos != null &&                                                         
 543                                  shortcut.dropPos != null &&                                                       
 544                                  modelShortcut.dropPos[0] == shortcut.dropPos[0] &&                                
 545                          modelShortcut.dropPos[1] == shortcut.dropPos[1]))) {                                      
 546                      // For all intents and purposes, this is the same object                                      
 547                      return;                                                                                       
 548                  }                                                                                                 
 549              }                                                                                                     
 550                                                                                                                    
 551              // the modelItem needs to match up perfectly with item if our model is                                
 552              // to be consistent with the database-- for now, just require                                         
 553              // modelItem == item or the equality check above                                                      
 554              String msg = "item: " + ((item != null) ? item.toString() : "null") +                                 
 555                      "modelItem: " +                                                                               
 556                      ((modelItem != null) ? modelItem.toString() : "null") +                                       
 557                      "Error: ItemInfo passed to checkItemInfo doesn't match original";                             
 558              RuntimeException e = new RuntimeException(msg);                                                       
 559              if (stackTrace != null) {                                                                             
 560                  e.setStackTrace(stackTrace);                                                                      
 561              }                                                                                                     
 562              throw e;                                                                                              
 563          }                                                                                                         
 564      }                                                                                                             
 565                                                                                                                    
 566      static void checkItemInfo(final ItemInfo item) {                                                              
 567          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 568          final long itemId = item.id;                                                                              
 569          Runnable r = new Runnable() {                                                                             
 570              public void run() {                                                                                   
 571                  synchronized (sBgLock) {                                                                          
 572                      checkItemInfoLocked(itemId, item, stackTrace);                                                
 573                  }                                                                                                 
 574              }                                                                                                     
 575          };                                                                                                        
 576          runOnWorkerThread(r);                                                                                     
 577      }                                                                                                             
 578                                                                                                                    
 579      static void updateItemInDatabaseHelper(Context context, final ContentValues values,                           
 580              final ItemInfo item, final String callingFunction) {                                                  
 581          final long itemId = item.id;                                                                              
 582          final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                                  
 583          final ContentResolver cr = context.getContentResolver();                                                  
 584                                                                                                                    
 585          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 586          Runnable r = new Runnable() {                                                                             
 587              public void run() {                                                                                   
 588                  cr.update(uri, values, null, null);                                                               
 589                  updateItemArrays(item, itemId, stackTrace);                                                       
 590              }                                                                                                     
 591          };                                                                                                        
 592          runOnWorkerThread(r);                                                                                     
 593      }                                                                                                             
 594                                                                                                                    
 595      static void updateItemsInDatabaseHelper(Context context, final ArrayList<ContentValues> valuesList,           
 596              final ArrayList<ItemInfo> items, final String callingFunction) {                                      
 597          final ContentResolver cr = context.getContentResolver();                                                  
 598                                                                                                                    
 599          final StackTraceElement[] stackTrace = new Throwable().getStackTrace();                                   
 600          Runnable r = new Runnable() {                                                                             
 601              public void run() {                                                                                   
 602                  ArrayList<ContentProviderOperation> ops =                                                         
 603                          new ArrayList<ContentProviderOperation>();                                                
 604                  int count = items.size();                                                                         
 605                  for (int i = 0; i < count; i++) {                                                                 
 606                      ItemInfo item = items.get(i);                                                                 
 607                      final long itemId = item.id;                                                                  
 608                      final Uri uri = LauncherSettings.Favorites.getContentUri(itemId, false);                      
 609                      ContentValues values = valuesList.get(i);                                                     
 610                                                                                                                    
 611                      ops.add(ContentProviderOperation.newUpdate(uri).withValues(values).build());                  
 612                      updateItemArrays(item, itemId, stackTrace);                                                   
 613                                                                                                                    
 614                  }                                                                                                 
 615                  try {                                                                                             
 616                      cr.applyBatch(LauncherProvider.AUTHORITY, ops);                                               
 617                  } catch (Exception e) {                                                                           
 618                      e.printStackTrace();                                                                          
 619                  }                                                                                                 
 620              }                                                                                                     
 621          };                                                                                                        
 622          runOnWorkerThread(r);                                                                                     
 623      }                                                                                                             
 624                                                                                                                    
 625      static void updateItemArrays(ItemInfo item, long itemId, StackTraceElement[] stackTrace) {                    
 626          // Lock on mBgLock *after* the db operation                                                               
 627          synchronized (sBgLock) {                                                                                  
 628              checkItemInfoLocked(itemId, item, stackTrace);                                                        
 629                                                                                                                    
 630              if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
 631                      item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                             
 632                  // Item is in a folder, make sure this folder exists                                              
 633                  if (!sBgFolders.containsKey(item.container)) {                                                    
 634                      // An items container is being set to a that of an item which is not in                       
 635                      // the list of Folders.                                                                       
 636                      String msg = "item: " + item + " container being set to: " +                                  
 637                              item.container + ", not in the list of folders";                                      
 638                      Log.e(TAG, msg);                                                                              
 639                  }                                                                                                 
 640              }                                                                                                     
 641                                                                                                                    
 642              // Items are added/removed from the corresponding FolderInfo elsewhere, such                          
 643              // as in Workspace.onDrop. Here, we just add/remove them from the list of items                       
 644              // that are on the desktop, as appropriate                                                            
 645              ItemInfo modelItem = sBgItemsIdMap.get(itemId);                                                       
 646              if (modelItem != null &&                                                                              
 647                      (modelItem.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                       
 648                       modelItem.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT)) {                      
 649                  switch (modelItem.itemType) {                                                                     
 650                      case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                        
 651                      case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                           
 652                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 653                          if (!sBgWorkspaceItems.contains(modelItem)) {                                             
 654                              sBgWorkspaceItems.add(modelItem);                                                     
 655                          }                                                                                         
 656                          break;                                                                                    
 657                      default:                                                                                      
 658                          break;                                                                                    
 659                  }                                                                                                 
 660              } else {                                                                                              
 661                  sBgWorkspaceItems.remove(modelItem);                                                              
 662              }                                                                                                     
 663          }                                                                                                         
 664      }                                                                                                             
 665                                                                                                                    
 666      public void flushWorkerThread() {                                                                             
 667          mFlushingWorkerThread = true;                                                                             
 668          Runnable waiter = new Runnable() {                                                                        
 669                  public void run() {                                                                               
 670                      synchronized (this) {                                                                         
 671                          notifyAll();                                                                              
 672                          mFlushingWorkerThread = false;                                                            
 673                      }                                                                                             
 674                  }                                                                                                 
 675              };                                                                                                    
 676                                                                                                                    
 677          synchronized(waiter) {                                                                                    
 678              runOnWorkerThread(waiter);                                                                            
 679              if (mLoaderTask != null) {                                                                            
 680                  synchronized(mLoaderTask) {                                                                       
 681                      mLoaderTask.notify();                                                                         
 682                  }                                                                                                 
 683              }                                                                                                     
 684              boolean success = false;                                                                              
 685              while (!success) {                                                                                    
 686                  try {                                                                                             
 687                      waiter.wait();                                                                                
 688                      success = true;                                                                               
 689                  } catch (InterruptedException e) {                                                                
 690                  }                                                                                                 
 691              }                                                                                                     
 692          }                                                                                                         
 693      }                                                                                                             
 694                                                                                                                    
 695      /**                                                                                                           
 696       * Move an item in the DB to a new <container, screen, cellX, cellY>                                          
 697       */                                                                                                           
 698      static void moveItemInDatabase(Context context, final ItemInfo item, final long container,                    
 699              final long screenId, final int cellX, final int cellY) {                                              
 700          item.container = container;                                                                               
 701          item.cellX = cellX;                                                                                       
 702          item.cellY = cellY;                                                                                       
 703                                                                                                                    
 704          // We store hotseat items in canonical form which is this orientation invariant position                  
 705          // in the hotseat                                                                                         
 706          if (context instanceof Launcher && screenId < 0 &&                                                        
 707                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 708              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 709          } else {                                                                                                  
 710              item.screenId = screenId;                                                                             
 711          }                                                                                                         
 712                                                                                                                    
 713          final ContentValues values = new ContentValues();                                                         
 714          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 715          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 716          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 717          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 718                                                                                                                    
 719          updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase");                                  
 720      }                                                                                                             
 721                                                                                                                    
 722      /**                                                                                                           
 723       * Move items in the DB to a new <container, screen, cellX, cellY>. We assume that the                        
 724       * cellX, cellY have already been updated on the ItemInfos.                                                   
 725       */                                                                                                           
 726      static void moveItemsInDatabase(Context context, final ArrayList<ItemInfo> items,                             
 727              final long container, final int screen) {                                                             
 728                                                                                                                    
 729          ArrayList<ContentValues> contentValues = new ArrayList<ContentValues>();                                  
 730          int count = items.size();                                                                                 
 731                                                                                                                    
 732          for (int i = 0; i < count; i++) {                                                                         
 733              ItemInfo item = items.get(i);                                                                         
 734              item.container = container;                                                                           
 735                                                                                                                    
 736              // We store hotseat items in canonical form which is this orientation invariant position              
 737              // in the hotseat                                                                                     
 738              if (context instanceof Launcher && screen < 0 &&                                                      
 739                      container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                  
 740                  item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(item.cellX,                   
 741                          item.cellY);                                                                              
 742              } else {                                                                                              
 743                  item.screenId = screen;                                                                           
 744              }                                                                                                     
 745                                                                                                                    
 746              final ContentValues values = new ContentValues();                                                     
 747              values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                     
 748              values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                             
 749              values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                             
 750              values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                         
 751                                                                                                                    
 752              contentValues.add(values);                                                                            
 753          }                                                                                                         
 754          updateItemsInDatabaseHelper(context, contentValues, items, "moveItemInDatabase");                         
 755      }                                                                                                             
 756                                                                                                                    
 757      /**                                                                                                           
 758       * Move and/or resize item in the DB to a new <container, screen, cellX, cellY, spanX, spanY>                 
 759       */                                                                                                           
 760      static void modifyItemInDatabase(Context context, final ItemInfo item, final long container,                  
 761              final long screenId, final int cellX, final int cellY, final int spanX, final int spanY) {            
 762          item.container = container;                                                                               
 763          item.cellX = cellX;                                                                                       
 764          item.cellY = cellY;                                                                                       
 765          item.spanX = spanX;                                                                                       
 766          item.spanY = spanY;                                                                                       
 767                                                                                                                    
 768          // We store hotseat items in canonical form which is this orientation invariant position                  
 769          // in the hotseat                                                                                         
 770          if (context instanceof Launcher && screenId < 0 &&                                                        
 771                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 772              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 773          } else {                                                                                                  
 774              item.screenId = screenId;                                                                             
 775          }                                                                                                         
 776                                                                                                                    
 777          final ContentValues values = new ContentValues();                                                         
 778          values.put(LauncherSettings.Favorites.CONTAINER, item.container);                                         
 779          values.put(LauncherSettings.Favorites.CELLX, item.cellX);                                                 
 780          values.put(LauncherSettings.Favorites.CELLY, item.cellY);                                                 
 781          values.put(LauncherSettings.Favorites.SPANX, item.spanX);                                                 
 782          values.put(LauncherSettings.Favorites.SPANY, item.spanY);                                                 
 783          values.put(LauncherSettings.Favorites.SCREEN, item.screenId);                                             
 784                                                                                                                    
 785          updateItemInDatabaseHelper(context, values, item, "modifyItemInDatabase");                                
 786      }                                                                                                             
 787                                                                                                                    
 788      /**                                                                                                           
 789       * Update an item to the database in a specified container.                                                   
 790       */                                                                                                           
 791      static void updateItemInDatabase(Context context, final ItemInfo item) {                                      
 792          final ContentValues values = new ContentValues();                                                         
 793          item.onAddToDatabase(values);                                                                             
 794          item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                         
 795          updateItemInDatabaseHelper(context, values, item, "updateItemInDatabase");                                
 796      }                                                                                                             
 797                                                                                                                    
 798      /**                                                                                                           
 799       * Returns true if the shortcuts already exists in the database.                                              
 800       * we identify a shortcut by its title and intent.                                                            
 801       */                                                                                                           
 802      static boolean shortcutExists(Context context, String title, Intent intent) {                                 
 803          final ContentResolver cr = context.getContentResolver();                                                  
 804          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 805              new String[] { "title", "intent" }, "title=? and intent=?",                                           
 806              new String[] { title, intent.toUri(0) }, null);                                                       
 807          boolean result = false;                                                                                   
 808          try {                                                                                                     
 809              result = c.moveToFirst();                                                                             
 810          } finally {                                                                                               
 811              c.close();                                                                                            
 812          }                                                                                                         
 813 +        return result;                                                                                            
 814 +    }                                                                                                             
 815 +                                                                                                                  
 816 +    /**                                                                                                           
 817 +     * Returns true if the shortcuts already exists in the database.                                              
 818 +     * we identify a shortcut by the component name of the intent.                                                
 819 +     */                                                                                                           
 820 +    static boolean appWasRestored(Context context, Intent intent) {                                               
 821 +        final ContentResolver cr = context.getContentResolver();                                                  
 822 +        final ComponentName component = intent.getComponent();                                                    
 823 +        if (component == null) {                                                                                  
 824 +            return false;                                                                                         
 825 +        }                                                                                                         
 826 +        String componentName = component.flattenToString();                                                       
 827 +        final String where = "intent glob \"*component=" + componentName + "*\" and restored = 1";                
 828 +        Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,                                               
 829 +                new String[]{"intent", "restored"}, where, null, null);                                           
 830 +        boolean result = false;                                                                                   
 831 +        try {                                                                                                     
 832 +            result = c.moveToFirst();                                                                             
 833 +        } finally {                                                                                               
 834 +            c.close();                                                                                            
 835 +        }                                                                                                         
 836 +        Log.d(TAG, "shortcutWasRestored is " + result + " for " + componentName);                                 
 837          return result;                                                                                            
 838      }                                                                                                             
 839                                                                                                                    
 840      /**                                                                                                           
 841       * Returns an ItemInfo array containing all the items in the LauncherModel.                                   
 842       * The ItemInfo.id is not set through this function.                                                          
 843       */                                                                                                           
 844      static ArrayList<ItemInfo> getItemsInLocalCoordinates(Context context) {                                      
 845          ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();                                                    
 846          final ContentResolver cr = context.getContentResolver();                                                  
 847          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] {                                
 848                  LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER,                       
 849                  LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CE🔵
 850                  LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null);          
 851                                                                                                                    
 852          final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);                  
 853          final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);                 
 854          final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);                       
 855          final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                         
 856          final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                         
 857          final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX);                         
 858          final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY);                         
 859                                                                                                                    
 860          try {                                                                                                     
 861              while (c.moveToNext()) {                                                                              
 862                  ItemInfo item = new ItemInfo();                                                                   
 863                  item.cellX = c.getInt(cellXIndex);                                                                
 864                  item.cellY = c.getInt(cellYIndex);                                                                
 865                  item.spanX = Math.max(1, c.getInt(spanXIndex));                                                   
 866                  item.spanY = Math.max(1, c.getInt(spanYIndex));                                                   
 867                  item.container = c.getInt(containerIndex);                                                        
 868                  item.itemType = c.getInt(itemTypeIndex);                                                          
 869                  item.screenId = c.getInt(screenIndex);                                                            
 870                                                                                                                    
 871                  items.add(item);                                                                                  
 872              }                                                                                                     
 873          } catch (Exception e) {                                                                                   
 874              items.clear();                                                                                        
 875          } finally {                                                                                               
 876              c.close();                                                                                            
 877          }                                                                                                         
 878                                                                                                                    
 879          return items;                                                                                             
 880      }                                                                                                             
 881                                                                                                                    
 882      /**                                                                                                           
 883       * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.                
 884       */                                                                                                           
 885      FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {                     
 886          final ContentResolver cr = context.getContentResolver();                                                  
 887          Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,                                         
 888                  "_id=? and (itemType=? or itemType=?)",                                                           
 889                  new String[] { String.valueOf(id),                                                                
 890                          String.valueOf(LauncherSettings.Favorites.ITEM_TYPE_FOLDER)}, null);                      
 891                                                                                                                    
 892          try {                                                                                                     
 893              if (c.moveToFirst()) {                                                                                
 894                  final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);          
 895                  final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);                 
 896                  final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);         
 897                  final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);               
 898                  final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);                 
 899                  final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);                 
 900                                                                                                                    
 901                  FolderInfo folderInfo = null;                                                                     
 902                  switch (c.getInt(itemTypeIndex)) {                                                                
 903                      case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                             
 904                          folderInfo = findOrMakeFolder(folderList, id);                                            
 905                          break;                                                                                    
 906                  }                                                                                                 
 907                                                                                                                    
 908                  folderInfo.title = c.getString(titleIndex);                                                       
 909                  folderInfo.id = id;                                                                               
 910                  folderInfo.container = c.getInt(containerIndex);                                                  
 911                  folderInfo.screenId = c.getInt(screenIndex);                                                      
 912                  folderInfo.cellX = c.getInt(cellXIndex);                                                          
 913                  folderInfo.cellY = c.getInt(cellYIndex);                                                          
 914                                                                                                                    
 915                  return folderInfo;                                                                                
 916              }                                                                                                     
 917          } finally {                                                                                               
 918              c.close();                                                                                            
 919          }                                                                                                         
 920                                                                                                                    
 921          return null;                                                                                              
 922      }                                                                                                             
 923                                                                                                                    
 924      /**                                                                                                           
 925       * Add an item to the database in a specified container. Sets the container, screen, cellX and                
 926       * cellY fields of the item. Also assigns an ID to the item.                                                  
 927       */                                                                                                           
 928      static void addItemToDatabase(Context context, final ItemInfo item, final long container,                     
 929              final long screenId, final int cellX, final int cellY, final boolean notify) {                        
 930          item.container = container;                                                                               
 931          item.cellX = cellX;                                                                                       
 932          item.cellY = cellY;                                                                                       
 933          // We store hotseat items in canonical form which is this orientation invariant position                  
 934          // in the hotseat                                                                                         
 935          if (context instanceof Launcher && screenId < 0 &&                                                        
 936                  container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                      
 937              item.screenId = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY);                    
 938          } else {                                                                                                  
 939              item.screenId = screenId;                                                                             
 940          }                                                                                                         
 941                                                                                                                    
 942          final ContentValues values = new ContentValues();                                                         
 943          final ContentResolver cr = context.getContentResolver();                                                  
 944          item.onAddToDatabase(values);                                                                             
 945                                                                                                                    
 946          item.id = LauncherAppState.getLauncherProvider().generateNewItemId();                                     
 947          values.put(LauncherSettings.Favorites._ID, item.id);                                                      
 948          item.updateValuesWithCoordinates(values, item.cellX, item.cellY);                                         
 949                                                                                                                    
 950          Runnable r = new Runnable() {                                                                             
 951              public void run() {                                                                                   
 952                  cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI :                                       
 953                          LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values);                          
 954                                                                                                                    
 955                  // Lock on mBgLock *after* the db operation                                                       
 956                  synchronized (sBgLock) {                                                                          
 957                      checkItemInfoLocked(item.id, item, null);                                                     
 958                      sBgItemsIdMap.put(item.id, item);                                                             
 959                      switch (item.itemType) {                                                                      
 960                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
 961                              sBgFolders.put(item.id, (FolderInfo) item);                                           
 962                              // Fall through                                                                       
 963                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
 964                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
 965                              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||                 
 966                                      item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {             
 967                                  sBgWorkspaceItems.add(item);                                                      
 968                              } else {                                                                              
 969                                  if (!sBgFolders.containsKey(item.container)) {                                    
 970                                      // Adding an item to a folder that doesn't exist.                             
 971                                      String msg = "adding item: " + item + " to a folder that " +                  
 972                                              " doesn't exist";                                                     
 973                                      Log.e(TAG, msg);                                                              
 974                                  }                                                                                 
 975                              }                                                                                     
 976                              break;                                                                                
 977                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
 978                              sBgAppWidgets.add((LauncherAppWidgetInfo) item);                                      
 979                              break;                                                                                
 980                      }                                                                                             
 981                  }                                                                                                 
 982              }                                                                                                     
 983          };                                                                                                        
 984          runOnWorkerThread(r);                                                                                     
 985      }                                                                                                             
 986                                                                                                                    
 987      /**                                                                                                           
 988       * Creates a new unique child id, for a given cell span across all layouts.                                   
 989       */                                                                                                           
 990      static int getCellLayoutChildId(                                                                              
 991              long container, long screen, int localCellX, int localCellY, int spanX, int spanY) {                  
 992          return (((int) container & 0xFF) << 24)                                                                   
 993                  | ((int) screen & 0xFF) << 16 | (localCellX & 0xFF) << 8 | (localCellY & 0xFF);                   
 994      }                                                                                                             
 995                                                                                                                    
 996      /**                                                                                                           
 997       * Removes the specified item from the database                                                               
 998       * @param context                                                                                             
 999       * @param item                                                                                                
1000       */                                                                                                           
1001      static void deleteItemFromDatabase(Context context, final ItemInfo item) {                                    
1002          final ContentResolver cr = context.getContentResolver();                                                  
1003          final Uri uriToDelete = LauncherSettings.Favorites.getContentUri(item.id, false);                         
1004                                                                                                                    
1005          Runnable r = new Runnable() {                                                                             
1006              public void run() {                                                                                   
1007                  cr.delete(uriToDelete, null, null);                                                               
1008                                                                                                                    
1009                  // Lock on mBgLock *after* the db operation                                                       
1010                  synchronized (sBgLock) {                                                                          
1011                      switch (item.itemType) {                                                                      
1012                          case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                         
1013                              sBgFolders.remove(item.id);                                                           
1014                              for (ItemInfo info: sBgItemsIdMap.values()) {                                         
1015                                  if (info.container == item.id) {                                                  
1016                                      // We are deleting a folder which still contains items that                   
1017                                      // think they are contained by that folder.                                   
1018                                      String msg = "deleting a folder (" + item + ") which still " +                
1019                                              "contains items (" + info + ")";                                      
1020                                      Log.e(TAG, msg);                                                              
1021                                  }                                                                                 
1022                              }                                                                                     
1023                              sBgWorkspaceItems.remove(item);                                                       
1024                              break;                                                                                
1025                          case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                    
1026                          case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                       
1027                              sBgWorkspaceItems.remove(item);                                                       
1028                              break;                                                                                
1029                          case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                      
1030                              sBgAppWidgets.remove((LauncherAppWidgetInfo) item);                                   
1031                              break;                                                                                
1032                      }                                                                                             
1033                      sBgItemsIdMap.remove(item.id);                                                                
1034                      sBgDbIconCache.remove(item);                                                                  
1035                  }                                                                                                 
1036              }                                                                                                     
1037          };                                                                                                        
1038          runOnWorkerThread(r);                                                                                     
1039      }                                                                                                             
1040                                                                                                                    
1041      /**                                                                                                           
1042       * Update the order of the workspace screens in the database. The array list contains                         
1043       * a list of screen ids in the order that they should appear.                                                 
1044       */                                                                                                           
1045      void updateWorkspaceScreenOrder(Context context, final ArrayList<Long> screens) {                             
1046          // Log to disk                                                                                            
1047          Launcher.addDumpLog(TAG, "11683562 - updateWorkspaceScreenOrder()", true);                                
1048          Launcher.addDumpLog(TAG, "11683562 -   screens: " + TextUtils.join(", ", screens), true);                 
1049                                                                                                                    
1050          final ArrayList<Long> screensCopy = new ArrayList<Long>(screens);                                         
1051          final ContentResolver cr = context.getContentResolver();                                                  
1052          final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                            
1053                                                                                                                    
1054          // Remove any negative screen ids -- these aren't persisted                                               
1055          Iterator<Long> iter = screensCopy.iterator();                                                             
1056          while (iter.hasNext()) {                                                                                  
1057              long id = iter.next();                                                                                
1058              if (id < 0) {                                                                                         
1059                  iter.remove();                                                                                    
1060              }                                                                                                     
1061          }                                                                                                         
1062                                                                                                                    
1063          Runnable r = new Runnable() {                                                                             
1064              @Override                                                                                             
1065              public void run() {                                                                                   
1066                  // Clear the table                                                                                
1067                  cr.delete(uri, null, null);                                                                       
1068                  int count = screensCopy.size();                                                                   
1069                  ContentValues[] values = new ContentValues[count];                                                
1070                  for (int i = 0; i < count; i++) {                                                                 
1071                      ContentValues v = new ContentValues();                                                        
1072                      long screenId = screensCopy.get(i);                                                           
1073                      v.put(LauncherSettings.WorkspaceScreens._ID, screenId);                                       
1074                      v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);                                      
1075                      values[i] = v;                                                                                
1076                  }                                                                                                 
1077                  cr.bulkInsert(uri, values);                                                                       
1078                                                                                                                    
1079                  synchronized (sBgLock) {                                                                          
1080                      sBgWorkspaceScreens.clear();                                                                  
1081                      sBgWorkspaceScreens.addAll(screensCopy);                                                      
1082                  }                                                                                                 
1083              }                                                                                                     
1084          };                                                                                                        
1085          runOnWorkerThread(r);                                                                                     
1086      }                                                                                                             
1087                                                                                                                    
1088      /**                                                                                                           
1089       * Remove the contents of the specified folder from the database                                              
1090       */                                                                                                           
1091      static void deleteFolderContentsFromDatabase(Context context, final FolderInfo info) {                        
1092          final ContentResolver cr = context.getContentResolver();                                                  
1093                                                                                                                    
1094          Runnable r = new Runnable() {                                                                             
1095              public void run() {                                                                                   
1096                  cr.delete(LauncherSettings.Favorites.getContentUri(info.id, false), null, null);                  
1097                  // Lock on mBgLock *after* the db operation                                                       
1098                  synchronized (sBgLock) {                                                                          
1099                      sBgItemsIdMap.remove(info.id);                                                                
1100                      sBgFolders.remove(info.id);                                                                   
1101                      sBgDbIconCache.remove(info);                                                                  
1102                      sBgWorkspaceItems.remove(info);                                                               
1103                  }                                                                                                 
1104                                                                                                                    
1105                  cr.delete(LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION,                                 
1106                          LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);                              
1107                  // Lock on mBgLock *after* the db operation                                                       
1108                  synchronized (sBgLock) {                                                                          
1109                      for (ItemInfo childInfo : info.contents) {                                                    
1110                          sBgItemsIdMap.remove(childInfo.id);                                                       
1111                          sBgDbIconCache.remove(childInfo);                                                         
1112                      }                                                                                             
1113                  }                                                                                                 
1114              }                                                                                                     
1115          };                                                                                                        
1116          runOnWorkerThread(r);                                                                                     
1117      }                                                                                                             
1118                                                                                                                    
1119      /**                                                                                                           
1120       * Set this as the current Launcher activity object for the loader.                                           
1121       */                                                                                                           
1122      public void initialize(Callbacks callbacks) {                                                                 
1123          synchronized (mLock) {                                                                                    
1124              mCallbacks = new WeakReference<Callbacks>(callbacks);                                                 
1125          }                                                                                                         
1126      }                                                                                                             
1127                                                                                                                    
1128      /**                                                                                                           
1129       * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and                                 
1130       * ACTION_PACKAGE_CHANGED.                                                                                    
1131       */                                                                                                           
1132      @Override                                                                                                     
1133      public void onReceive(Context context, Intent intent) {                                                       
1134          if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent);                                              
1135                                                                                                                    
1136          final String action = intent.getAction();                                                                 
1137                                                                                                                    
1138          if (Intent.ACTION_PACKAGE_CHANGED.equals(action)                                                          
1139                  || Intent.ACTION_PACKAGE_REMOVED.equals(action)                                                   
1140                  || Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                                  
1141              final String packageName = intent.getData().getSchemeSpecificPart();                                  
1142              final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);                      
1143                                                                                                                    
1144              int op = PackageUpdatedTask.OP_NONE;                                                                  
1145                                                                                                                    
1146              if (packageName == null || packageName.length() == 0) {                                               
1147                  // they sent us a bad intent                                                                      
1148                  return;                                                                                           
1149              }                                                                                                     
1150                                                                                                                    
1151              if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {                                                   
1152                  op = PackageUpdatedTask.OP_UPDATE;                                                                
1153              } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {                                            
1154                  if (!replacing) {                                                                                 
1155                      op = PackageUpdatedTask.OP_REMOVE;                                                            
1156                  }                                                                                                 
1157                  // else, we are replacing the package, so a PACKAGE_ADDED will be sent                            
1158                  // later, we will update the package at this time                                                 
1159              } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {                                              
1160                  if (!replacing) {                                                                                 
1161                      op = PackageUpdatedTask.OP_ADD;                                                               
1162                  } else {                                                                                          
1163                      op = PackageUpdatedTask.OP_UPDATE;                                                            
1164                  }                                                                                                 
1165              }                                                                                                     
1166                                                                                                                    
1167              if (op != PackageUpdatedTask.OP_NONE) {                                                               
1168                  enqueuePackageUpdated(new PackageUpdatedTask(op, new String[] { packageName }));                  
1169              }                                                                                                     
1170                                                                                                                    
1171          } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {                                
1172              final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);                      
1173              String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);                    
1174              if (!replacing) {                                                                                     
1175                  enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_ADD, packages));               
1176                  if (mAppsCanBeOnRemoveableStorage) {                                                              
1177                      // Only rebind if we support removable storage.  It catches the case where                    
1178                      // apps on the external sd card need to be reloaded                                           
1179                      startLoaderFromBackground();                                                                  
1180                  }                                                                                                 
1181              } else {                                                                                              
1182                  // If we are replacing then just update the packages in the list                                  
1183                  enqueuePackageUpdated(new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE,                        
1184                          packages));                                                                               
1185              }                                                                                                     
1186          } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {                              
1187              final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);                      
1188              if (!replacing) {                                                                                     
1189                  String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);                
1190                  enqueuePackageUpdated(new PackageUpdatedTask(                                                     
1191                              PackageUpdatedTask.OP_UNAVAILABLE, packages));                                        
1192              }                                                                                                     
1193              // else, we are replacing the packages, so ignore this event and wait for                             
1194              // EXTERNAL_APPLICATIONS_AVAILABLE to update the packages at that time                                
1195          } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {                                                 
1196              // If we have changed locale we need to clear out the labels in all apps/workspace.                   
1197              forceReload();                                                                                        
1198          } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {                                          
1199               // Check if configuration change was an mcc/mnc change which would affect app resources              
1200               // and we would need to clear out the labels in all apps/workspace. Same handling as                 
1201               // above for ACTION_LOCALE_CHANGED                                                                   
1202               Configuration currentConfig = context.getResources().getConfiguration();                             
1203               if (mPreviousConfigMcc != currentConfig.mcc) {                                                       
1204                     Log.d(TAG, "Reload apps on config change. curr_mcc:"                                           
1205                         + currentConfig.mcc + " prevmcc:" + mPreviousConfigMcc);                                   
1206                     forceReload();                                                                                 
1207               }                                                                                                    
1208               // Update previousConfig                                                                             
1209               mPreviousConfigMcc = currentConfig.mcc;                                                              
1210          } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) ||                          
1211                     SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) {                              
1212              if (mCallbacks != null) {                                                                             
1213                  Callbacks callbacks = mCallbacks.get();                                                           
1214                  if (callbacks != null) {                                                                          
1215                      callbacks.bindSearchablesChanged();                                                           
1216                  }                                                                                                 
1217              }                                                                                                     
1218          }                                                                                                         
1219      }                                                                                                             
1220                                                                                                                    
1221      private void forceReload() {                                                                                  
1222          resetLoadedState(true, true);                                                                             
1223                                                                                                                    
1224          // Do this here because if the launcher activity is running it will be restarted.                         
1225          // If it's not running startLoaderFromBackground will merely tell it that it needs                        
1226          // to reload.                                                                                             
1227          startLoaderFromBackground();                                                                              
1228      }                                                                                                             
1229                                                                                                                    
1230      public void resetLoadedState(boolean resetAllAppsLoaded, boolean resetWorkspaceLoaded) {                      
1231          synchronized (mLock) {                                                                                    
1232              // Stop any existing loaders first, so they don't set mAllAppsLoaded or                               
1233              // mWorkspaceLoaded to true later                                                                     
1234              stopLoaderLocked();                                                                                   
1235              if (resetAllAppsLoaded) mAllAppsLoaded = false;                                                       
1236              if (resetWorkspaceLoaded) mWorkspaceLoaded = false;                                                   
1237          }                                                                                                         
1238      }                                                                                                             
1239                                                                                                                    
1240      /**                                                                                                           
1241       * When the launcher is in the background, it's possible for it to miss paired                                
1242       * configuration changes.  So whenever we trigger the loader from the background                              
1243       * tell the launcher that it needs to re-run the loader when it comes back instead                            
1244       * of doing it now.                                                                                           
1245       */                                                                                                           
1246      public void startLoaderFromBackground() {                                                                     
1247          boolean runLoader = false;                                                                                
1248          if (mCallbacks != null) {                                                                                 
1249              Callbacks callbacks = mCallbacks.get();                                                               
1250              if (callbacks != null) {                                                                              
1251                  // Only actually run the loader if they're not paused.                                            
1252                  if (!callbacks.setLoadOnResume()) {                                                               
1253                      runLoader = true;                                                                             
1254                  }                                                                                                 
1255              }                                                                                                     
1256          }                                                                                                         
1257          if (runLoader) {                                                                                          
1258              startLoader(false, PagedView.INVALID_RESTORE_PAGE);                                                   
1259          }                                                                                                         
1260      }                                                                                                             
1261                                                                                                                    
1262      // If there is already a loader task running, tell it to stop.                                                
1263      // returns true if isLaunching() was true on the old task                                                     
1264      private boolean stopLoaderLocked() {                                                                          
1265          boolean isLaunching = false;                                                                              
1266          LoaderTask oldTask = mLoaderTask;                                                                         
1267          if (oldTask != null) {                                                                                    
1268              if (oldTask.isLaunching()) {                                                                          
1269                  isLaunching = true;                                                                               
1270              }                                                                                                     
1271              oldTask.stopLocked();                                                                                 
1272          }                                                                                                         
1273          return isLaunching;                                                                                       
1274      }                                                                                                             
1275                                                                                                                    
1276      public void startLoader(boolean isLaunching, int synchronousBindPage) {                                       
1277          startLoader(isLaunching, synchronousBindPage, LOADER_FLAG_NONE);                                          
1278      }                                                                                                             
1279                                                                                                                    
1280      public void startLoader(boolean isLaunching, int synchronousBindPage, int loadFlags) {                        
1281          synchronized (mLock) {                                                                                    
1282              if (DEBUG_LOADERS) {                                                                                  
1283                  Log.d(TAG, "startLoader isLaunching=" + isLaunching);                                             
1284              }                                                                                                     
1285                                                                                                                    
1286              // Clear any deferred bind-runnables from the synchronized load process                               
1287              // We must do this before any loading/binding is scheduled below.                                     
1288              mDeferredBindRunnables.clear();                                                                       
1289                                                                                                                    
1290              // Don't bother to start the thread if we know it's not going to do anything                          
1291              if (mCallbacks != null && mCallbacks.get() != null) {                                                 
1292                  // If there is already one running, tell it to stop.                                              
1293                  // also, don't downgrade isLaunching if we're already running                                     
1294                  isLaunching = isLaunching || stopLoaderLocked();                                                  
1295                  mLoaderTask = new LoaderTask(mApp.getContext(), isLaunching, loadFlags);                          
1296                  if (synchronousBindPage != PagedView.INVALID_RESTORE_PAGE                                         
1297                          && mAllAppsLoaded && mWorkspaceLoaded) {                                                  
1298                      mLoaderTask.runBindSynchronousPage(synchronousBindPage);                                      
1299                  } else {                                                                                          
1300                      sWorkerThread.setPriority(Thread.NORM_PRIORITY);                                              
1301                      sWorker.post(mLoaderTask);                                                                    
1302                  }                                                                                                 
1303              }                                                                                                     
1304          }                                                                                                         
1305      }                                                                                                             
1306                                                                                                                    
1307      void bindRemainingSynchronousPages() {                                                                        
1308          // Post the remaining side pages to be loaded                                                             
1309          if (!mDeferredBindRunnables.isEmpty()) {                                                                  
1310              for (final Runnable r : mDeferredBindRunnables) {                                                     
1311                  mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);                                                   
1312              }                                                                                                     
1313              mDeferredBindRunnables.clear();                                                                       
1314          }                                                                                                         
1315      }                                                                                                             
1316                                                                                                                    
1317      public void stopLoader() {                                                                                    
1318          synchronized (mLock) {                                                                                    
1319              if (mLoaderTask != null) {                                                                            
1320                  mLoaderTask.stopLocked();                                                                         
1321              }                                                                                                     
1322          }                                                                                                         
1323      }                                                                                                             
1324                                                                                                                    
1325      /** Loads the workspace screens db into a map of Rank -> ScreenId */                                          
1326      private static TreeMap<Integer, Long> loadWorkspaceScreensDb(Context context) {                               
1327          final ContentResolver contentResolver = context.getContentResolver();                                     
1328          final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI;                                     
1329          final Cursor sc = contentResolver.query(screensUri, null, null, null, null);                              
1330          TreeMap<Integer, Long> orderedScreens = new TreeMap<Integer, Long>();                                     
1331                                                                                                                    
1332          try {                                                                                                     
1333              final int idIndex = sc.getColumnIndexOrThrow(                                                         
1334                      LauncherSettings.WorkspaceScreens._ID);                                                       
1335              final int rankIndex = sc.getColumnIndexOrThrow(                                                       
1336                      LauncherSettings.WorkspaceScreens.SCREEN_RANK);                                               
1337              while (sc.moveToNext()) {                                                                             
1338                  try {                                                                                             
1339                      long screenId = sc.getLong(idIndex);                                                          
1340                      int rank = sc.getInt(rankIndex);                                                              
1341                      orderedScreens.put(rank, screenId);                                                           
1342                  } catch (Exception e) {                                                                           
1343                      Launcher.addDumpLog(TAG, "Desktop items loading interrupted - invalid screens: " + e, true);  
1344                  }                                                                                                 
1345              }                                                                                                     
1346          } finally {                                                                                               
1347              sc.close();                                                                                           
1348          }                                                                                                         
1349                                                                                                                    
1350          // Log to disk                                                                                            
1351          Launcher.addDumpLog(TAG, "11683562 - loadWorkspaceScreensDb()", true);                                    
1352          ArrayList<String> orderedScreensPairs= new ArrayList<String>();                                           
1353          for (Integer i : orderedScreens.keySet()) {                                                               
1354              orderedScreensPairs.add("{ " + i + ": " + orderedScreens.get(i) + " }");                              
1355          }                                                                                                         
1356          Launcher.addDumpLog(TAG, "11683562 -   screens: " +                                                       
1357                  TextUtils.join(", ", orderedScreensPairs), true);                                                 
1358          return orderedScreens;                                                                                    
1359      }                                                                                                             
1360                                                                                                                    
1361      public boolean isAllAppsLoaded() {                                                                            
1362          return mAllAppsLoaded;                                                                                    
1363      }                                                                                                             
1364                                                                                                                    
1365      boolean isLoadingWorkspace() {                                                                                
1366          synchronized (mLock) {                                                                                    
1367              if (mLoaderTask != null) {                                                                            
1368                  return mLoaderTask.isLoadingWorkspace();                                                          
1369              }                                                                                                     
1370          }                                                                                                         
1371          return false;                                                                                             
1372      }                                                                                                             
1373                                                                                                                    
1374      /**                                                                                                           
1375       * Runnable for the thread that loads the contents of the launcher:                                           
1376       *   - workspace icons                                                                                        
1377       *   - widgets                                                                                                
1378       *   - all apps icons                                                                                         
1379       */                                                                                                           
1380      private class LoaderTask implements Runnable {                                                                
1381          private Context mContext;                                                                                 
1382          private boolean mIsLaunching;                                                                             
1383          private boolean mIsLoadingAndBindingWorkspace;                                                            
1384          private boolean mStopped;                                                                                 
1385          private boolean mLoadAndBindStepFinished;                                                                 
1386          private int mFlags;                                                                                       
1387                                                                                                                    
1388          private HashMap<Object, CharSequence> mLabelCache;                                                        
1389                                                                                                                    
1390          LoaderTask(Context context, boolean isLaunching, int flags) {                                             
1391              mContext = context;                                                                                   
1392              mIsLaunching = isLaunching;                                                                           
1393              mLabelCache = new HashMap<Object, CharSequence>();                                                    
1394              mFlags = flags;                                                                                       
1395          }                                                                                                         
1396                                                                                                                    
1397          boolean isLaunching() {                                                                                   
1398              return mIsLaunching;                                                                                  
1399          }                                                                                                         
1400                                                                                                                    
1401          boolean isLoadingWorkspace() {                                                                            
1402              return mIsLoadingAndBindingWorkspace;                                                                 
1403          }                                                                                                         
1404                                                                                                                    
1405          /** Returns whether this is an upgrade path */                                                            
1406          private boolean loadAndBindWorkspace() {                                                                  
1407              mIsLoadingAndBindingWorkspace = true;                                                                 
1408                                                                                                                    
1409              // Load the workspace                                                                                 
1410              if (DEBUG_LOADERS) {                                                                                  
1411                  Log.d(TAG, "loadAndBindWorkspace mWorkspaceLoaded=" + mWorkspaceLoaded);                          
1412              }                                                                                                     
1413                                                                                                                    
1414              boolean isUpgradePath = false;                                                                        
1415              if (!mWorkspaceLoaded) {                                                                              
1416                  isUpgradePath = loadWorkspace();                                                                  
1417                  synchronized (LoaderTask.this) {                                                                  
1418                      if (mStopped) {                                                                               
1419                          return isUpgradePath;                                                                     
1420                      }                                                                                             
1421                      mWorkspaceLoaded = true;                                                                      
1422                  }                                                                                                 
1423              }                                                                                                     
1424                                                                                                                    
1425              // Bind the workspace                                                                                 
1426              bindWorkspace(-1, isUpgradePath);                                                                     
1427              return isUpgradePath;                                                                                 
1428          }                                                                                                         
1429                                                                                                                    
1430          private void waitForIdle() {                                                                              
1431              // Wait until the either we're stopped or the other threads are done.                                 
1432              // This way we don't start loading all apps until the workspace has settled                           
1433              // down.                                                                                              
1434              synchronized (LoaderTask.this) {                                                                      
1435                  final long workspaceWaitTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                    
1436                                                                                                                    
1437                  mHandler.postIdle(new Runnable() {                                                                
1438                          public void run() {                                                                       
1439                              synchronized (LoaderTask.this) {                                                      
1440                                  mLoadAndBindStepFinished = true;                                                  
1441                                  if (DEBUG_LOADERS) {                                                              
1442                                      Log.d(TAG, "done with previous binding step");                                
1443                                  }                                                                                 
1444                                  LoaderTask.this.notify();                                                         
1445                              }                                                                                     
1446                          }                                                                                         
1447                      });                                                                                           
1448                                                                                                                    
1449                  while (!mStopped && !mLoadAndBindStepFinished && !mFlushingWorkerThread) {                        
1450                      try {                                                                                         
1451                          // Just in case mFlushingWorkerThread changes but we aren't woken up,                     
1452                          // wait no longer than 1sec at a time                                                     
1453                          this.wait(1000);                                                                          
1454                      } catch (InterruptedException ex) {                                                           
1455                          // Ignore                                                                                 
1456                      }                                                                                             
1457                  }                                                                                                 
1458                  if (DEBUG_LOADERS) {                                                                              
1459                      Log.d(TAG, "waited "                                                                          
1460                              + (SystemClock.uptimeMillis()-workspaceWaitTime)                                      
1461                              + "ms for previous step to finish binding");                                          
1462                  }                                                                                                 
1463              }                                                                                                     
1464          }                                                                                                         
1465                                                                                                                    
1466          void runBindSynchronousPage(int synchronousBindPage) {                                                    
1467              if (synchronousBindPage == PagedView.INVALID_RESTORE_PAGE) {                                          
1468                  // Ensure that we have a valid page index to load synchronously                                   
1469                  throw new RuntimeException("Should not call runBindSynchronousPage() without " +                  
1470                          "valid page index");                                                                      
1471              }                                                                                                     
1472              if (!mAllAppsLoaded || !mWorkspaceLoaded) {                                                           
1473                  // Ensure that we don't try and bind a specified page when the pages have not been                
1474                  // loaded already (we should load everything asynchronously in that case)                         
1475                  throw new RuntimeException("Expecting AllApps and Workspace to be loaded");                       
1476              }                                                                                                     
1477              synchronized (mLock) {                                                                                
1478                  if (mIsLoaderTaskRunning) {                                                                       
1479                      // Ensure that we are never running the background loading at this point since                
1480                      // we also touch the background collections                                                   
1481                      throw new RuntimeException("Error! Background loading is already running");                   
1482                  }                                                                                                 
1483              }                                                                                                     
1484                                                                                                                    
1485              // XXX: Throw an exception if we are already loading (since we touch the worker thread                
1486              //      data structures, we can't allow any other thread to touch that data, but because              
1487              //      this call is synchronous, we can get away with not locking).                                  
1488                                                                                                                    
1489              // The LauncherModel is static in the LauncherAppState and mHandler may have queued                   
1490              // operations from the previous activity.  We need to ensure that all queued operations               
1491              // are executed before any synchronous binding work is done.                                          
1492              mHandler.flush();                                                                                     
1493                                                                                                                    
1494              // Divide the set of loaded items into those that we are binding synchronously, and                   
1495              // everything else that is to be bound normally (asynchronously).                                     
1496              bindWorkspace(synchronousBindPage, false);                                                            
1497              // XXX: For now, continue posting the binding of AllApps as there are other issues that               
1498              //      arise from that.                                                                              
1499              onlyBindAllApps();                                                                                    
1500          }                                                                                                         
1501                                                                                                                    
1502          public void run() {                                                                                       
1503              boolean isUpgrade = false;                                                                            
1504                                                                                                                    
1505              synchronized (mLock) {                                                                                
1506                  mIsLoaderTaskRunning = true;                                                                      
1507              }                                                                                                     
1508              // Optimize for end-user experience: if the Launcher is up and // running with the                    
1509              // All Apps interface in the foreground, load All Apps first. Otherwise, load the                     
1510              // workspace first (default).                                                                         
1511              keep_running: {                                                                                       
1512                  // Elevate priority when Home launches for the first time to avoid                                
1513                  // starving at boot time. Staring at a blank home is not cool.                                    
1514                  synchronized (mLock) {                                                                            
1515                      if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to " +                                 
1516                              (mIsLaunching ? "DEFAULT" : "BACKGROUND"));                                           
1517                      android.os.Process.setThreadPriority(mIsLaunching                                             
1518                              ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND);              
1519                  }                                                                                                 
1520                  if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace");                                       
1521                  isUpgrade = loadAndBindWorkspace();                                                               
1522                                                                                                                    
1523                  if (mStopped) {                                                                                   
1524                      break keep_running;                                                                           
1525                  }                                                                                                 
1526                                                                                                                    
1527                  // Whew! Hard work done.  Slow us down, and wait until the UI thread has                          
1528                  // settled down.                                                                                  
1529                  synchronized (mLock) {                                                                            
1530                      if (mIsLaunching) {                                                                           
1531                          if (DEBUG_LOADERS) Log.d(TAG, "Setting thread priority to BACKGROUND");                   
1532                          android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);                 
1533                      }                                                                                             
1534                  }                                                                                                 
1535                  waitForIdle();                                                                                    
1536                                                                                                                    
1537                  // second step                                                                                    
1538                  if (DEBUG_LOADERS) Log.d(TAG, "step 2: loading all apps");                                        
1539                  loadAndBindAllApps();                                                                             
1540                                                                                                                    
1541                  // Restore the default thread priority after we are done loading items                            
1542                  synchronized (mLock) {                                                                            
1543                      android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);                        
1544                  }                                                                                                 
1545              }                                                                                                     
1546                                                                                                                    
1547              // Update the saved icons if necessary                                                                
1548              if (DEBUG_LOADERS) Log.d(TAG, "Comparing loaded icons to database icons");                            
1549              synchronized (sBgLock) {                                                                              
1550                  for (Object key : sBgDbIconCache.keySet()) {                                                      
1551                      updateSavedIcon(mContext, (ShortcutInfo) key, sBgDbIconCache.get(key));                       
1552                  }                                                                                                 
1553                  sBgDbIconCache.clear();                                                                           
1554              }                                                                                                     
1555                                                                                                                    
1556              if (LauncherAppState.isDisableAllApps()) {                                                            
1557                  // Ensure that all the applications that are in the system are                                    
1558                  // represented on the home screen.                                                                
1559                  if (!UPGRADE_USE_MORE_APPS_FOLDER || !isUpgrade) {                                                
1560                      verifyApplications();                                                                         
1561                  }                                                                                                 
1562              }                                                                                                     
1563                                                                                                                    
1564              // Clear out this reference, otherwise we end up holding it until all of the                          
1565              // callback runnables are done.                                                                       
1566              mContext = null;                                                                                      
1567                                                                                                                    
1568              synchronized (mLock) {                                                                                
1569                  // If we are still the last one to be scheduled, remove ourselves.                                
1570                  if (mLoaderTask == this) {                                                                        
1571                      mLoaderTask = null;                                                                           
1572                  }                                                                                                 
1573                  mIsLoaderTaskRunning = false;                                                                     
1574              }                                                                                                     
1575          }                                                                                                         
1576                                                                                                                    
1577          public void stopLocked() {                                                                                
1578              synchronized (LoaderTask.this) {                                                                      
1579                  mStopped = true;                                                                                  
1580                  this.notify();                                                                                    
1581              }                                                                                                     
1582          }                                                                                                         
1583                                                                                                                    
1584          /**                                                                                                       
1585           * Gets the callbacks object.  If we've been stopped, or if the launcher object                           
1586           * has somehow been garbage collected, return null instead.  Pass in the Callbacks                        
1587           * object that was around when the deferred message was scheduled, and if there's                         
1588           * a new Callbacks object around then also return null.  This will save us from                           
1589           * calling onto it with data that will be ignored.                                                        
1590           */                                                                                                       
1591          Callbacks tryGetCallbacks(Callbacks oldCallbacks) {                                                       
1592              synchronized (mLock) {                                                                                
1593                  if (mStopped) {                                                                                   
1594                      return null;                                                                                  
1595                  }                                                                                                 
1596                                                                                                                    
1597                  if (mCallbacks == null) {                                                                         
1598                      return null;                                                                                  
1599                  }                                                                                                 
1600                                                                                                                    
1601                  final Callbacks callbacks = mCallbacks.get();                                                     
1602                  if (callbacks != oldCallbacks) {                                                                  
1603                      return null;                                                                                  
1604                  }                                                                                                 
1605                  if (callbacks == null) {                                                                          
1606                      Log.w(TAG, "no mCallbacks");                                                                  
1607                      return null;                                                                                  
1608                  }                                                                                                 
1609                                                                                                                    
1610                  return callbacks;                                                                                 
1611              }                                                                                                     
1612          }                                                                                                         
1613                                                                                                                    
1614          private void verifyApplications() {                                                                       
1615              final Context context = mApp.getContext();                                                            
1616                                                                                                                    
1617              // Cross reference all the applications in our apps list with items in the workspace                  
1618              ArrayList<ItemInfo> tmpInfos;                                                                         
1619              ArrayList<ItemInfo> added = new ArrayList<ItemInfo>();                                                
1620              synchronized (sBgLock) {                                                                              
1621                  for (AppInfo app : mBgAllAppsList.data) {                                                         
1622                      tmpInfos = getItemInfoForComponentName(app.componentName);                                    
1623                      if (tmpInfos.isEmpty()) {                                                                     
1624                          // We are missing an application icon, so add this to the workspace                       
1625                          added.add(app);                                                                           
1626                          // This is a rare event, so lets log it                                                   
1627                          Log.e(TAG, "Missing Application on load: " + app);                                        
1628                      }                                                                                             
1629                  }                                                                                                 
1630              }                                                                                                     
1631              if (!added.isEmpty()) {                                                                               
1632                  addAndBindAddedWorkspaceApps(context, added);                                                     


1633              }                                                                                                     
1634          }                                                                                                         
1635                                                                                                                    
1636          // check & update map of what's occupied; used to discard overlapping/invalid items                       
1637          private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item,                   
1638                                             AtomicBoolean deleteOnInvalidPlacement) {                              
1639              LauncherAppState app = LauncherAppState.getInstance();                                                
1640              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1641              final int countX = (int) grid.numColumns;                                                             
1642              final int countY = (int) grid.numRows;                                                                
1643                                                                                                                    
1644              long containerIndex = item.screenId;                                                                  
1645              if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                                 
1646                  // Return early if we detect that an item is under the hotseat button                             
1647                  if (mCallbacks == null ||                                                                         
1648                          mCallbacks.get().isAllAppsButtonRank((int) item.screenId)) {                              
1649                      deleteOnInvalidPlacement.set(true);                                                           
1650                      Log.e(TAG, "Error loading shortcut into hotseat " + item                                      
1651                              + " into position (" + item.screenId + ":" + item.cellX + ","                         
1652                              + item.cellY + ") occupied by all apps");                                             
1653                      return false;                                                                                 
1654                  }                                                                                                 
1655                                                                                                                    
1656                  final ItemInfo[][] hotseatItems =                                                                 
1657                          occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);                        
1658                                                                                                                    
1659                  if (item.screenId >= grid.numHotseatIcons) {                                                      
1660                      Log.e(TAG, "Error loading shortcut " + item                                                   
1661                              + " into hotseat position " + item.screenId                                           
1662                              + ", position out of bounds: (0 to " + (grid.numHotseatIcons - 1)                     
1663                              + ")");                                                                               
1664                      return false;                                                                                 
1665                  }                                                                                                 
1666                                                                                                                    
1667                  if (hotseatItems != null) {                                                                       
1668                      if (hotseatItems[(int) item.screenId][0] != null) {                                           
1669                          Log.e(TAG, "Error loading shortcut into hotseat " + item                                  
1670                                  + " into position (" + item.screenId + ":" + item.cellX + ","                     
1671                                  + item.cellY + ") occupied by "                                                   
1672                                  + occupied.get(LauncherSettings.Favorites.CONTAINER_HOTSEAT)                      
1673                                  [(int) item.screenId][0]);                                                        
1674                              return false;                                                                         
1675                      } else {                                                                                      
1676                          hotseatItems[(int) item.screenId][0] = item;                                              
1677                          return true;                                                                              
1678                      }                                                                                             
1679                  } else {                                                                                          
1680                      final ItemInfo[][] items = new ItemInfo[(int) grid.numHotseatIcons][1];                       
1681                      items[(int) item.screenId][0] = item;                                                         
1682                      occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, items);                     
1683                      return true;                                                                                  
1684                  }                                                                                                 
1685              } else if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) {                          
1686                  // Skip further checking if it is not the hotseat or workspace container                          
1687                  return true;                                                                                      
1688              }                                                                                                     
1689                                                                                                                    
1690              if (!occupied.containsKey(item.screenId)) {                                                           
1691                  ItemInfo[][] items = new ItemInfo[countX + 1][countY + 1];                                        
1692                  occupied.put(item.screenId, items);                                                               
1693              }                                                                                                     
1694                                                                                                                    
1695              final ItemInfo[][] screens = occupied.get(item.screenId);                                             
1696              if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                                 
1697                      item.cellX < 0 || item.cellY < 0 ||                                                           
1698                      item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {                       
1699                  Log.e(TAG, "Error loading shortcut " + item                                                       
1700                          + " into cell (" + containerIndex + "-" + item.screenId + ":"                             
1701                          + item.cellX + "," + item.cellY                                                           
1702                          + ") out of screen bounds ( " + countX + "x" + countY + ")");                             
1703                  return false;                                                                                     
1704              }                                                                                                     
1705                                                                                                                    
1706              // Check if any workspace icons overlap with each other                                               
1707              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1708                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1709                      if (screens[x][y] != null) {                                                                  
1710                          Log.e(TAG, "Error loading shortcut " + item                                               
1711                              + " into cell (" + containerIndex + "-" + item.screenId + ":"                         
1712                              + x + "," + y                                                                         
1713                              + ") occupied by "                                                                    
1714                              + screens[x][y]);                                                                     
1715                          return false;                                                                             
1716                      }                                                                                             
1717                  }                                                                                                 
1718              }                                                                                                     
1719              for (int x = item.cellX; x < (item.cellX+item.spanX); x++) {                                          
1720                  for (int y = item.cellY; y < (item.cellY+item.spanY); y++) {                                      
1721                      screens[x][y] = item;                                                                         
1722                  }                                                                                                 
1723              }                                                                                                     
1724                                                                                                                    
1725              return true;                                                                                          
1726          }                                                                                                         
1727                                                                                                                    
1728          /** Clears all the sBg data structures */                                                                 
1729          private void clearSBgDataStructures() {                                                                   
1730              synchronized (sBgLock) {                                                                              
1731                  sBgWorkspaceItems.clear();                                                                        
1732                  sBgAppWidgets.clear();                                                                            
1733                  sBgFolders.clear();                                                                               
1734                  sBgItemsIdMap.clear();                                                                            
1735                  sBgDbIconCache.clear();                                                                           
1736                  sBgWorkspaceScreens.clear();                                                                      
1737              }                                                                                                     
1738          }                                                                                                         
1739                                                                                                                    
1740          /** Returns whether this is an upgrade path */                                                            
1741          private boolean loadWorkspace() {                                                                         
1742              // Log to disk                                                                                        
1743              Launcher.addDumpLog(TAG, "11683562 - loadWorkspace()", true);                                         
1744                                                                                                                    
1745              final long t = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                        
1746                                                                                                                    
1747              final Context context = mContext;                                                                     
1748              final ContentResolver contentResolver = context.getContentResolver();                                 
1749              final PackageManager manager = context.getPackageManager();                                           
1750              final AppWidgetManager widgets = AppWidgetManager.getInstance(context);                               
1751              final boolean isSafeMode = manager.isSafeMode();                                                      
1752                                                                                                                    
1753              LauncherAppState app = LauncherAppState.getInstance();                                                
1754              DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                         
1755              int countX = (int) grid.numColumns;                                                                   
1756              int countY = (int) grid.numRows;                                                                      
1757                                                                                                                    
1758              if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) {                                                    
1759                  Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true);                     
1760                  LauncherAppState.getLauncherProvider().deleteDatabase();                                          
1761              }                                                                                                     
1762                                                                                                                    
1763              if ((mFlags & LOADER_FLAG_MIGRATE_SHORTCUTS) != 0) {                                                  
1764                  // append the user's Launcher2 shortcuts                                                          
1765                  Launcher.addDumpLog(TAG, "loadWorkspace: migrating from launcher2", true);                        
1766                  LauncherAppState.getLauncherProvider().migrateLauncher2Shortcuts();                               
1767              } else {                                                                                              
1768                  // Make sure the default workspace is loaded                                                      
1769                  Launcher.addDumpLog(TAG, "loadWorkspace: loading default favorites", false);                      
1770                  LauncherAppState.getLauncherProvider().loadDefaultFavoritesIfNecessary(0);                        
1771              }                                                                                                     
1772                                                                                                                    
1773              // Check if we need to do any upgrade-path logic                                                      
1774              // (Includes having just imported default favorites)                                                  
1775              boolean loadedOldDb = LauncherAppState.getLauncherProvider().justLoadedOldDb();                       
1776                                                                                                                    
1777              // Log to disk                                                                                        
1778              Launcher.addDumpLog(TAG, "11683562 -   loadedOldDb: " + loadedOldDb, true);                           
1779                                                                                                                    
1780              synchronized (sBgLock) {                                                                              
1781                  clearSBgDataStructures();                                                                         
1782                                                                                                                    
1783                  final ArrayList<Long> itemsToRemove = new ArrayList<Long>();                                      
1784                  final ArrayList<Long> restoredRows = new ArrayList<Long>();                                       
1785                  final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;                                    
1786                  if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);                                
1787                  final Cursor c = contentResolver.query(contentUri, null, null, null, null);                       
1788                                                                                                                    
1789                  // +1 for the hotseat (it can be larger than the workspace)                                       
1790                  // Load workspace in reverse order to ensure that latest items are loaded first (and              
1791                  // before any earlier duplicates)                                                                 
1792                  final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();                   
1793                                                                                                                    
1794                  try {                                                                                             
1795                      final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);                  
1796                      final int intentIndex = c.getColumnIndexOrThrow                                               
1797                              (LauncherSettings.Favorites.INTENT);                                                  
1798                      final int titleIndex = c.getColumnIndexOrThrow                                                
1799                              (LauncherSettings.Favorites.TITLE);                                                   
1800                      final int iconTypeIndex = c.getColumnIndexOrThrow(                                            
1801                              LauncherSettings.Favorites.ICON_TYPE);                                                
1802                      final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);               
1803                      final int iconPackageIndex = c.getColumnIndexOrThrow(                                         
1804                              LauncherSettings.Favorites.ICON_PACKAGE);                                             
1805                      final int iconResourceIndex = c.getColumnIndexOrThrow(                                        
1806                              LauncherSettings.Favorites.ICON_RESOURCE);                                            
1807                      final int containerIndex = c.getColumnIndexOrThrow(                                           
1808                              LauncherSettings.Favorites.CONTAINER);                                                
1809                      final int itemTypeIndex = c.getColumnIndexOrThrow(                                            
1810                              LauncherSettings.Favorites.ITEM_TYPE);                                                
1811                      final int appWidgetIdIndex = c.getColumnIndexOrThrow(                                         
1812                              LauncherSettings.Favorites.APPWIDGET_ID);                                             
1813                      final int appWidgetProviderIndex = c.getColumnIndexOrThrow(                                   
1814                              LauncherSettings.Favorites.APPWIDGET_PROVIDER);                                       
1815                      final int screenIndex = c.getColumnIndexOrThrow(                                              
1816                              LauncherSettings.Favorites.SCREEN);                                                   
1817                      final int cellXIndex = c.getColumnIndexOrThrow                                                
1818                              (LauncherSettings.Favorites.CELLX);                                                   
1819                      final int cellYIndex = c.getColumnIndexOrThrow                                                
1820                              (LauncherSettings.Favorites.CELLY);                                                   
1821                      final int spanXIndex = c.getColumnIndexOrThrow                                                
1822                              (LauncherSettings.Favorites.SPANX);                                                   
1823                      final int spanYIndex = c.getColumnIndexOrThrow(                                               
1824                              LauncherSettings.Favorites.SPANY);                                                    
1825                      final int restoredIndex = c.getColumnIndexOrThrow(                                            
1826                              LauncherSettings.Favorites.RESTORED);                                                 
1827                      //final int uriIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.URI);               
1828                      //final int displayModeIndex = c.getColumnIndexOrThrow(                                       
1829                      //        LauncherSettings.Favorites.DISPLAY_MODE);                                           
1830                                                                                                                    
1831                      ShortcutInfo info;                                                                            
1832                      String intentDescription;                                                                     
1833                      LauncherAppWidgetInfo appWidgetInfo;                                                          
1834                      int container;                                                                                
1835                      long id;                                                                                      
1836                      Intent intent;                                                                                
1837                                                                                                                    
1838                      while (!mStopped && c.moveToNext()) {                                                         
1839                          AtomicBoolean deleteOnInvalidPlacement = new AtomicBoolean(false);                        
1840                          try {                                                                                     
1841                              int itemType = c.getInt(itemTypeIndex);                                               
1842                              boolean restored = 0 != c.getInt(restoredIndex);                                      
1843                                                                                                                    
1844                              switch (itemType) {                                                                   
1845                              case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:                                
1846                              case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:                                   
1847                                  id = c.getLong(idIndex);                                                          
1848                                  intentDescription = c.getString(intentIndex);                                     
1849                                  try {                                                                             
1850                                      intent = Intent.parseUri(intentDescription, 0);                               
1851                                      ComponentName cn = intent.getComponent();                                     
1852                                      if (cn != null && !isValidPackageComponent(manager, cn)) {                    
1853                                          if (restored) {                                                           
1854                                              // might be installed later                                           
1855                                              Launcher.addDumpLog(TAG,                                              
1856                                                      "package not yet restored: " + cn, true);                     
1857                                          } else {                                                                  
1858                                              if (!mAppsCanBeOnRemoveableStorage) {                                 
1859                                                  // Log the invalid package, and remove it                         
1860                                                  Launcher.addDumpLog(TAG,                                          
1861                                                          "Invalid package removed: " + cn, true);                  
1862                                                  itemsToRemove.add(id);                                            
1863                                              } else {                                                              
1864                                                  // If apps can be on external storage, then we just               
1865                                                  // leave them for the user to remove (maybe add                   
1866                                                  // visual treatment to it)                                        
1867                                                  Launcher.addDumpLog(TAG,                                          
1868                                                          "Invalid package found: " + cn, true);                    
1869                                              }                                                                     
1870                                              continue;                                                             
1871                                          }                                                                         
1872                                      } else if (restored) {                                                        
1873                                          // no special handling necessary for this restored item                   
1874                                          restoredRows.add(id);                                                     
1875                                          restored = false;                                                         
1876                                      }                                                                             
1877                                  } catch (URISyntaxException e) {                                                  
1878                                      Launcher.addDumpLog(TAG,                                                      
1879                                              "Invalid uri: " + intentDescription, true);                           
1880                                      continue;                                                                     
1881                                  }                                                                                 
1882                                                                                                                    
1883                                  if (restored) {                                                                   
1884                                      Launcher.addDumpLog(TAG,                                                      
1885                                              "constructing info for partially restored package",                   
1886                                              true);                                                                
1887 -                                    info = getRestoredItemInfo(c, titleIndex);                                    
1888 +                                    info = getRestoredItemInfo(c, titleIndex, intent);                            
1889                                      intent = getRestoredItemIntent(c, context, intent);                           
1890                                  } else if (itemType ==                                                            
1891                                          LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {                       
1892                                      info = getShortcutInfo(manager, intent, context, c, iconIndex,                
1893                                              titleIndex, mLabelCache);                                             
1894                                  } else {                                                                          
1895                                      info = getShortcutInfo(c, context, iconTypeIndex,                             
1896                                              iconPackageIndex, iconResourceIndex, iconIndex,                       
1897                                              titleIndex);                                                          
1898                                                                                                                    
1899                                      // App shortcuts that used to be automatically added to Launcher              
1900                                      // didn't always have the correct intent flags set, so do that                
1901                                      // here                                                                       
1902                                      if (intent.getAction() != null &&                                             
1903                                          intent.getCategories() != null &&                                         
1904                                          intent.getAction().equals(Intent.ACTION_MAIN) &&                          
1905                                          intent.getCategories().contains(Intent.CATEGORY_LAUNCHER)) {              
1906                                          intent.addFlags(                                                          
1907                                              Intent.FLAG_ACTIVITY_NEW_TASK |                                       
1908                                              Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);                           
1909                                      }                                                                             
1910                                  }                                                                                 
1911                                                                                                                    
1912                                  if (info != null) {                                                               
1913                                      info.id = id;                                                                 
1914                                      info.intent = intent;                                                         
1915                                      container = c.getInt(containerIndex);                                         
1916                                      info.container = container;                                                   
1917                                      info.screenId = c.getInt(screenIndex);                                        
1918                                      info.cellX = c.getInt(cellXIndex);                                            
1919                                      info.cellY = c.getInt(cellYIndex);                                            
1920                                      info.spanX = 1;                                                               
1921                                      info.spanY = 1;                                                               
1922                                                                                                                    
1923                                      // check & update map of what's occupied                                      
1924                                      deleteOnInvalidPlacement.set(false);                                          
1925                                      if (!checkItemPlacement(occupied, info, deleteOnInvalidPlacement)) {          
1926                                          if (deleteOnInvalidPlacement.get()) {                                     
1927                                              itemsToRemove.add(id);                                                
1928                                          }                                                                         
1929                                          break;                                                                    
1930                                      }                                                                             
1931                                                                                                                    
1932                                      switch (container) {                                                          
1933                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
1934                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
1935                                          sBgWorkspaceItems.add(info);                                              
1936                                          break;                                                                    
1937                                      default:                                                                      
1938                                          // Item is in a user folder                                               
1939                                          FolderInfo folderInfo =                                                   
1940                                                  findOrMakeFolder(sBgFolders, container);                          
1941                                          folderInfo.add(info);                                                     
1942                                          break;                                                                    
1943                                      }                                                                             
1944                                      sBgItemsIdMap.put(info.id, info);                                             
1945                                                                                                                    
1946                                      // now that we've loaded everthing re-save it with the                        
1947                                      // icon in case it disappears somehow.                                        
1948                                      queueIconToBeChecked(sBgDbIconCache, info, c, iconIndex);                     
1949                                  } else {                                                                          
1950                                      throw new RuntimeException("Unexpected null ShortcutInfo");                   
1951                                  }                                                                                 
1952                                  break;                                                                            
1953                                                                                                                    
1954                              case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:                                     
1955                                  id = c.getLong(idIndex);                                                          
1956                                  FolderInfo folderInfo = findOrMakeFolder(sBgFolders, id);                         
1957                                                                                                                    
1958                                  folderInfo.title = c.getString(titleIndex);                                       
1959                                  folderInfo.id = id;                                                               
1960                                  container = c.getInt(containerIndex);                                             
1961                                  folderInfo.container = container;                                                 
1962                                  folderInfo.screenId = c.getInt(screenIndex);                                      
1963                                  folderInfo.cellX = c.getInt(cellXIndex);                                          
1964                                  folderInfo.cellY = c.getInt(cellYIndex);                                          
1965                                  folderInfo.spanX = 1;                                                             
1966                                  folderInfo.spanY = 1;                                                             
1967                                                                                                                    
1968                                  // check & update map of what's occupied                                          
1969                                  deleteOnInvalidPlacement.set(false);                                              
1970                                  if (!checkItemPlacement(occupied, folderInfo,                                     
1971                                          deleteOnInvalidPlacement)) {                                              
1972                                      if (deleteOnInvalidPlacement.get()) {                                         
1973                                          itemsToRemove.add(id);                                                    
1974                                      }                                                                             
1975                                      break;                                                                        
1976                                  }                                                                                 
1977                                                                                                                    
1978                                  switch (container) {                                                              
1979                                      case LauncherSettings.Favorites.CONTAINER_DESKTOP:                            
1980                                      case LauncherSettings.Favorites.CONTAINER_HOTSEAT:                            
1981                                          sBgWorkspaceItems.add(folderInfo);                                        
1982                                          break;                                                                    
1983                                  }                                                                                 
1984                                                                                                                    
1985                                  if (restored) {                                                                   
1986                                      // no special handling required for restored folders                          
1987                                      restoredRows.add(id);                                                         
1988                                  }                                                                                 
1989                                                                                                                    
1990                                  sBgItemsIdMap.put(folderInfo.id, folderInfo);                                     
1991                                  sBgFolders.put(folderInfo.id, folderInfo);                                        
1992                                  break;                                                                            
1993                                                                                                                    
1994                              case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:                                  
1995                                  // Read all Launcher-specific widget details                                      
1996                                  int appWidgetId = c.getInt(appWidgetIdIndex);                                     
1997                                  String savedProvider = c.getString(appWidgetProviderIndex);                       
1998                                                                                                                    
1999                                  id = c.getLong(idIndex);                                                          
2000                                                                                                                    
2001                                  final AppWidgetProviderInfo provider =                                            
2002                                          widgets.getAppWidgetInfo(appWidgetId);                                    
2003                                                                                                                    
2004                                  if (!isSafeMode && (provider == null || provider.provider == null ||              
2005                                          provider.provider.getPackageName() == null)) {                            
2006                                      String log = "Deleting widget that isn't installed anymore: id="              
2007                                          + id + " appWidgetId=" + appWidgetId;                                     
2008                                      Log.e(TAG, log);                                                              
2009                                      Launcher.addDumpLog(TAG, log, false);                                         
2010                                      itemsToRemove.add(id);                                                        
2011                                  } else {                                                                          
2012                                      appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,                        
2013                                              provider.provider);                                                   
2014                                      appWidgetInfo.id = id;                                                        
2015                                      appWidgetInfo.screenId = c.getInt(screenIndex);                               
2016                                      appWidgetInfo.cellX = c.getInt(cellXIndex);                                   
2017                                      appWidgetInfo.cellY = c.getInt(cellYIndex);                                   
2018                                      appWidgetInfo.spanX = c.getInt(spanXIndex);                                   
2019                                      appWidgetInfo.spanY = c.getInt(spanYIndex);                                   
2020                                      int[] minSpan = Launcher.getMinSpanForWidget(context, provider);              
2021                                      appWidgetInfo.minSpanX = minSpan[0];                                          
2022                                      appWidgetInfo.minSpanY = minSpan[1];                                          
2023                                                                                                                    
2024                                      container = c.getInt(containerIndex);                                         
2025                                      if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&              
2026                                          container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {              
2027                                          Log.e(TAG, "Widget found where container != " +                           
2028                                              "CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");               
2029                                          continue;                                                                 
2030                                      }                                                                             
2031                                                                                                                    
2032                                      appWidgetInfo.container = c.getInt(containerIndex);                           
2033                                      // check & update map of what's occupied                                      
2034                                      deleteOnInvalidPlacement.set(false);                                          
2035                                      if (!checkItemPlacement(occupied, appWidgetInfo,                              
2036                                              deleteOnInvalidPlacement)) {                                          
2037                                          if (deleteOnInvalidPlacement.get()) {                                     
2038                                              itemsToRemove.add(id);                                                
2039                                          }                                                                         
2040                                          break;                                                                    
2041                                      }                                                                             
2042                                      String providerName = provider.provider.flattenToString();                    
2043                                      if (!providerName.equals(savedProvider)) {                                    
2044                                          ContentValues values = new ContentValues();                               
2045                                          values.put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,                 
2046                                                  providerName);                                                    
2047                                          String where = BaseColumns._ID + "= ?";                                   
2048                                          String[] args = {Integer.toString(c.getInt(idIndex))};                    
2049                                          contentResolver.update(contentUri, values, where, args);                  
2050                                      }                                                                             
2051                                      sBgItemsIdMap.put(appWidgetInfo.id, appWidgetInfo);                           
2052                                      sBgAppWidgets.add(appWidgetInfo);                                             
2053                                  }                                                                                 
2054                                  break;                                                                            
2055                              }                                                                                     
2056                          } catch (Exception e) {                                                                   
2057                              Launcher.addDumpLog(TAG, "Desktop items loading interrupted", e, true);               
2058                          }                                                                                         
2059                      }                                                                                             
2060                  } finally {                                                                                       
2061                      if (c != null) {                                                                              
2062                          c.close();                                                                                
2063                      }                                                                                             
2064                  }                                                                                                 
2065                                                                                                                    
2066                  // Break early if we've stopped loading                                                           
2067                  if (mStopped) {                                                                                   
2068                      clearSBgDataStructures();                                                                     
2069                      return false;                                                                                 
2070                  }                                                                                                 
2071                                                                                                                    
2072                  if (itemsToRemove.size() > 0) {                                                                   
2073                      ContentProviderClient client = contentResolver.acquireContentProviderClient(                  
2074                              LauncherSettings.Favorites.CONTENT_URI);                                              
2075                      // Remove dead items                                                                          
2076                      for (long id : itemsToRemove) {                                                               
2077                          if (DEBUG_LOADERS) {                                                                      
2078                              Log.d(TAG, "Removed id = " + id);                                                     
2079                          }                                                                                         
2080                          // Don't notify content observers                                                         
2081                          try {                                                                                     
2082                              client.delete(LauncherSettings.Favorites.getContentUri(id, false),                    
2083                                      null, null);                                                                  
2084                          } catch (RemoteException e) {                                                             
2085                              Log.w(TAG, "Could not remove id = " + id);                                            
2086                          }                                                                                         
2087                      }                                                                                             
2088                  }                                                                                                 
2089                                                                                                                    
2090                  if (restoredRows.size() > 0) {                                                                    
2091                      ContentProviderClient updater = contentResolver.acquireContentProviderClient(                 
2092                              LauncherSettings.Favorites.CONTENT_URI);                                              
2093                      // Update restored items that no longer require special handling                              
2094                      try {                                                                                         
2095                          StringBuilder selectionBuilder = new StringBuilder();                                     
2096                          selectionBuilder.append(LauncherSettings.Favorites._ID);                                  
2097                          selectionBuilder.append(" IN (");                                                         
2098                          selectionBuilder.append(TextUtils.join(", ", restoredRows));                              
2099                          selectionBuilder.append(")");                                                             
2100                          ContentValues values = new ContentValues();                                               
2101                          values.put(LauncherSettings.Favorites.RESTORED, 0);                                       
2102                          updater.update(LauncherSettings.Favorites.CONTENT_URI,                                    
2103                                  values, selectionBuilder.toString(), null);                                       
2104                      } catch (RemoteException e) {                                                                 
2105                          Log.w(TAG, "Could not update restored rows");                                             
2106                      }                                                                                             
2107                  }                                                                                                 
2108                                                                                                                    
2109                  if (loadedOldDb) {                                                                                
2110                      long maxScreenId = 0;                                                                         
2111                      // If we're importing we use the old screen order.                                            
2112                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2113                          long screenId = item.screenId;                                                            
2114                          if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2115                                  !sBgWorkspaceScreens.contains(screenId)) {                                        
2116                              sBgWorkspaceScreens.add(screenId);                                                    
2117                              if (screenId > maxScreenId) {                                                         
2118                                  maxScreenId = screenId;                                                           
2119                              }                                                                                     
2120                          }                                                                                         
2121                      }                                                                                             
2122                      Collections.sort(sBgWorkspaceScreens);                                                        
2123                      // Log to disk                                                                                
2124                      Launcher.addDumpLog(TAG, "11683562 -   maxScreenId: " + maxScreenId, true);                   
2125                      Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2126                              TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2127                                                                                                                    
2128                      LauncherAppState.getLauncherProvider().updateMaxScreenId(maxScreenId);                        
2129                      updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                     
2130                                                                                                                    
2131                      // Update the max item id after we load an old db                                             
2132                      long maxItemId = 0;                                                                           
2133                      // If we're importing we use the old screen order.                                            
2134                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2135                          maxItemId = Math.max(maxItemId, item.id);                                                 
2136                      }                                                                                             
2137                      LauncherAppState.getLauncherProvider().updateMaxItemId(maxItemId);                            
2138                  } else {                                                                                          
2139                      TreeMap<Integer, Long> orderedScreens = loadWorkspaceScreensDb(mContext);                     
2140                      for (Integer i : orderedScreens.keySet()) {                                                   
2141                          sBgWorkspaceScreens.add(orderedScreens.get(i));                                           
2142                      }                                                                                             
2143                      // Log to disk                                                                                
2144                      Launcher.addDumpLog(TAG, "11683562 -   sBgWorkspaceScreens: " +                               
2145                              TextUtils.join(", ", sBgWorkspaceScreens), true);                                     
2146                                                                                                                    
2147                      // Remove any empty screens                                                                   
2148                      ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);                     
2149                      for (ItemInfo item: sBgItemsIdMap.values()) {                                                 
2150                          long screenId = item.screenId;                                                            
2151                          if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                     
2152                                  unusedScreens.contains(screenId)) {                                               
2153                              unusedScreens.remove(screenId);                                                       
2154                          }                                                                                         
2155                      }                                                                                             
2156                                                                                                                    
2157                      // If there are any empty screens remove them, and update.                                    
2158                      if (unusedScreens.size() != 0) {                                                              
2159                          // Log to disk                                                                            
2160                          Launcher.addDumpLog(TAG, "11683562 -   unusedScreens (to be removed): " +                 
2161                                  TextUtils.join(", ", unusedScreens), true);                                       
2162                                                                                                                    
2163                          sBgWorkspaceScreens.removeAll(unusedScreens);                                             
2164                          updateWorkspaceScreenOrder(context, sBgWorkspaceScreens);                                 
2165                      }                                                                                             
2166                  }                                                                                                 
2167                                                                                                                    
2168                  if (DEBUG_LOADERS) {                                                                              
2169                      Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");                   
2170                      Log.d(TAG, "workspace layout: ");                                                             
2171                      int nScreens = occupied.size();                                                               
2172                      for (int y = 0; y < countY; y++) {                                                            
2173                          String line = "";                                                                         
2174                                                                                                                    
2175                          Iterator<Long> iter = occupied.keySet().iterator();                                       
2176                          while (iter.hasNext()) {                                                                  
2177                              long screenId = iter.next();                                                          
2178                              if (screenId > 0) {                                                                   
2179                                  line += " | ";                                                                    
2180                              }                                                                                     
2181                              for (int x = 0; x < countX; x++) {                                                    
2182                                  line += ((occupied.get(screenId)[x][y] != null) ? "#" : ".");                     
2183                              }                                                                                     
2184                          }                                                                                         
2185                          Log.d(TAG, "[ " + line + " ]");                                                           
2186                      }                                                                                             
2187                  }                                                                                                 
2188              }                                                                                                     
2189              return loadedOldDb;                                                                                   
2190          }                                                                                                         
2191                                                                                                                    
2192          /** Filters the set of items who are directly or indirectly (via another container) on the                
2193           * specified screen. */                                                                                   
2194          private void filterCurrentWorkspaceItems(long currentScreenId,                                            
2195                  ArrayList<ItemInfo> allWorkspaceItems,                                                            
2196                  ArrayList<ItemInfo> currentScreenItems,                                                           
2197                  ArrayList<ItemInfo> otherScreenItems) {                                                           
2198              // Purge any null ItemInfos                                                                           
2199              Iterator<ItemInfo> iter = allWorkspaceItems.iterator();                                               
2200              while (iter.hasNext()) {                                                                              
2201                  ItemInfo i = iter.next();                                                                         
2202                  if (i == null) {                                                                                  
2203                      iter.remove();                                                                                
2204                  }                                                                                                 
2205              }                                                                                                     
2206                                                                                                                    
2207              // Order the set of items by their containers first, this allows use to walk through the              
2208              // list sequentially, build up a list of containers that are in the specified screen,                 
2209              // as well as all items in those containers.                                                          
2210              Set<Long> itemsOnScreen = new HashSet<Long>();                                                        
2211              Collections.sort(allWorkspaceItems, new Comparator<ItemInfo>() {                                      
2212                  @Override                                                                                         
2213                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2214                      return (int) (lhs.container - rhs.container);                                                 
2215                  }                                                                                                 
2216              });                                                                                                   
2217              for (ItemInfo info : allWorkspaceItems) {                                                             
2218                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {                             
2219                      if (info.screenId == currentScreenId) {                                                       
2220                          currentScreenItems.add(info);                                                             
2221                          itemsOnScreen.add(info.id);                                                               
2222                      } else {                                                                                      
2223                          otherScreenItems.add(info);                                                               
2224                      }                                                                                             
2225                  } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {                      
2226                      currentScreenItems.add(info);                                                                 
2227                      itemsOnScreen.add(info.id);                                                                   
2228                  } else {                                                                                          
2229                      if (itemsOnScreen.contains(info.container)) {                                                 
2230                          currentScreenItems.add(info);                                                             
2231                          itemsOnScreen.add(info.id);                                                               
2232                      } else {                                                                                      
2233                          otherScreenItems.add(info);                                                               
2234                      }                                                                                             
2235                  }                                                                                                 
2236              }                                                                                                     
2237          }                                                                                                         
2238                                                                                                                    
2239          /** Filters the set of widgets which are on the specified screen. */                                      
2240          private void filterCurrentAppWidgets(long currentScreenId,                                                
2241                  ArrayList<LauncherAppWidgetInfo> appWidgets,                                                      
2242                  ArrayList<LauncherAppWidgetInfo> currentScreenWidgets,                                            
2243                  ArrayList<LauncherAppWidgetInfo> otherScreenWidgets) {                                            
2244                                                                                                                    
2245              for (LauncherAppWidgetInfo widget : appWidgets) {                                                     
2246                  if (widget == null) continue;                                                                     
2247                  if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                           
2248                          widget.screenId == currentScreenId) {                                                     
2249                      currentScreenWidgets.add(widget);                                                             
2250                  } else {                                                                                          
2251                      otherScreenWidgets.add(widget);                                                               
2252                  }                                                                                                 
2253              }                                                                                                     
2254          }                                                                                                         
2255                                                                                                                    
2256          /** Filters the set of folders which are on the specified screen. */                                      
2257          private void filterCurrentFolders(long currentScreenId,                                                   
2258                  HashMap<Long, ItemInfo> itemsIdMap,                                                               
2259                  HashMap<Long, FolderInfo> folders,                                                                
2260                  HashMap<Long, FolderInfo> currentScreenFolders,                                                   
2261                  HashMap<Long, FolderInfo> otherScreenFolders) {                                                   
2262                                                                                                                    
2263              for (long id : folders.keySet()) {                                                                    
2264                  ItemInfo info = itemsIdMap.get(id);                                                               
2265                  FolderInfo folder = folders.get(id);                                                              
2266                  if (info == null || folder == null) continue;                                                     
2267                  if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&                             
2268                          info.screenId == currentScreenId) {                                                       
2269                      currentScreenFolders.put(id, folder);                                                         
2270                  } else {                                                                                          
2271                      otherScreenFolders.put(id, folder);                                                           
2272                  }                                                                                                 
2273              }                                                                                                     
2274          }                                                                                                         
2275                                                                                                                    
2276          /** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to                   
2277           * right) */                                                                                              
2278          private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {                            
2279              final LauncherAppState app = LauncherAppState.getInstance();                                          
2280              final DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();                                   
2281              // XXX: review this                                                                                   
2282              Collections.sort(workspaceItems, new Comparator<ItemInfo>() {                                         
2283                  @Override                                                                                         
2284                  public int compare(ItemInfo lhs, ItemInfo rhs) {                                                  
2285                      int cellCountX = (int) grid.numColumns;                                                       
2286                      int cellCountY = (int) grid.numRows;                                                          
2287                      int screenOffset = cellCountX * cellCountY;                                                   
2288                      int containerOffset = screenOffset * (Launcher.SCREEN_COUNT + 1); // +1 hotseat               
2289                      long lr = (lhs.container * containerOffset + lhs.screenId * screenOffset +                    
2290                              lhs.cellY * cellCountX + lhs.cellX);                                                  
2291                      long rr = (rhs.container * containerOffset + rhs.screenId * screenOffset +                    
2292                              rhs.cellY * cellCountX + rhs.cellX);                                                  
2293                      return (int) (lr - rr);                                                                       
2294                  }                                                                                                 
2295              });                                                                                                   
2296          }                                                                                                         
2297                                                                                                                    
2298          private void bindWorkspaceScreens(final Callbacks oldCallbacks,                                           
2299                  final ArrayList<Long> orderedScreens) {                                                           
2300              final Runnable r = new Runnable() {                                                                   
2301                  @Override                                                                                         
2302                  public void run() {                                                                               
2303                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2304                      if (callbacks != null) {                                                                      
2305                          callbacks.bindScreens(orderedScreens);                                                    
2306                      }                                                                                             
2307                  }                                                                                                 
2308              };                                                                                                    
2309              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2310          }                                                                                                         
2311                                                                                                                    
2312          private void bindWorkspaceItems(final Callbacks oldCallbacks,                                             
2313                  final ArrayList<ItemInfo> workspaceItems,                                                         
2314                  final ArrayList<LauncherAppWidgetInfo> appWidgets,                                                
2315                  final HashMap<Long, FolderInfo> folders,                                                          
2316                  ArrayList<Runnable> deferredBindRunnables) {                                                      
2317                                                                                                                    
2318              final boolean postOnMainThread = (deferredBindRunnables != null);                                     
2319                                                                                                                    
2320              // Bind the workspace items                                                                           
2321              int N = workspaceItems.size();                                                                        
2322              for (int i = 0; i < N; i += ITEMS_CHUNK) {                                                            
2323                  final int start = i;                                                                              
2324                  final int chunkSize = (i+ITEMS_CHUNK <= N) ? ITEMS_CHUNK : (N-i);                                 
2325                  final Runnable r = new Runnable() {                                                               
2326                      @Override                                                                                     
2327                      public void run() {                                                                           
2328                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2329                          if (callbacks != null) {                                                                  
2330                              callbacks.bindItems(workspaceItems, start, start+chunkSize,                           
2331                                      false);                                                                       
2332                          }                                                                                         
2333                      }                                                                                             
2334                  };                                                                                                
2335                  if (postOnMainThread) {                                                                           
2336                      deferredBindRunnables.add(r);                                                                 
2337                  } else {                                                                                          
2338                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2339                  }                                                                                                 
2340              }                                                                                                     
2341                                                                                                                    
2342              // Bind the folders                                                                                   
2343              if (!folders.isEmpty()) {                                                                             
2344                  final Runnable r = new Runnable() {                                                               
2345                      public void run() {                                                                           
2346                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2347                          if (callbacks != null) {                                                                  
2348                              callbacks.bindFolders(folders);                                                       
2349                          }                                                                                         
2350                      }                                                                                             
2351                  };                                                                                                
2352                  if (postOnMainThread) {                                                                           
2353                      deferredBindRunnables.add(r);                                                                 
2354                  } else {                                                                                          
2355                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2356                  }                                                                                                 
2357              }                                                                                                     
2358                                                                                                                    
2359              // Bind the widgets, one at a time                                                                    
2360              N = appWidgets.size();                                                                                
2361              for (int i = 0; i < N; i++) {                                                                         
2362                  final LauncherAppWidgetInfo widget = appWidgets.get(i);                                           
2363                  final Runnable r = new Runnable() {                                                               
2364                      public void run() {                                                                           
2365                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2366                          if (callbacks != null) {                                                                  
2367                              callbacks.bindAppWidget(widget);                                                      
2368                          }                                                                                         
2369                      }                                                                                             
2370                  };                                                                                                
2371                  if (postOnMainThread) {                                                                           
2372                      deferredBindRunnables.add(r);                                                                 
2373                  } else {                                                                                          
2374                      runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                             
2375                  }                                                                                                 
2376              }                                                                                                     
2377          }                                                                                                         
2378                                                                                                                    
2379          /**                                                                                                       
2380           * Binds all loaded data to actual views on the main thread.                                              
2381           */                                                                                                       
2382          private void bindWorkspace(int synchronizeBindPage, final boolean isUpgradePath) {                        
2383              final long t = SystemClock.uptimeMillis();                                                            
2384              Runnable r;                                                                                           
2385                                                                                                                    
2386              // Don't use these two variables in any of the callback runnables.                                    
2387              // Otherwise we hold a reference to them.                                                             
2388              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2389              if (oldCallbacks == null) {                                                                           
2390                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2391                  Log.w(TAG, "LoaderTask running with no launcher");                                                
2392                  return;                                                                                           
2393              }                                                                                                     
2394                                                                                                                    
2395              // Save a copy of all the bg-thread collections                                                       
2396              ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();                                       
2397              ArrayList<LauncherAppWidgetInfo> appWidgets =                                                         
2398                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2399              HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();                                  
2400              HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();                                   
2401              ArrayList<Long> orderedScreenIds = new ArrayList<Long>();                                             
2402              synchronized (sBgLock) {                                                                              
2403                  workspaceItems.addAll(sBgWorkspaceItems);                                                         
2404                  appWidgets.addAll(sBgAppWidgets);                                                                 
2405                  folders.putAll(sBgFolders);                                                                       
2406                  itemsIdMap.putAll(sBgItemsIdMap);                                                                 
2407                  orderedScreenIds.addAll(sBgWorkspaceScreens);                                                     
2408              }                                                                                                     
2409                                                                                                                    
2410              final boolean isLoadingSynchronously =                                                                
2411                      synchronizeBindPage != PagedView.INVALID_RESTORE_PAGE;                                        
2412              int currScreen = isLoadingSynchronously ? synchronizeBindPage :                                       
2413                  oldCallbacks.getCurrentWorkspaceScreen();                                                         
2414              if (currScreen >= orderedScreenIds.size()) {                                                          
2415                  // There may be no workspace screens (just hotseat items and an empty page).                      
2416                  currScreen = PagedView.INVALID_RESTORE_PAGE;                                                      
2417              }                                                                                                     
2418              final int currentScreen = currScreen;                                                                 
2419              final long currentScreenId = currentScreen < 0                                                        
2420                      ? INVALID_SCREEN_ID : orderedScreenIds.get(currentScreen);                                    
2421                                                                                                                    
2422              // Load all the items that are on the current page first (and in the process, unbind                  
2423              // all the existing workspace items before we call startBinding() below.                              
2424              unbindWorkspaceItemsOnMainThread();                                                                   
2425                                                                                                                    
2426              // Separate the items that are on the current screen, and all the other remaining items               
2427              ArrayList<ItemInfo> currentWorkspaceItems = new ArrayList<ItemInfo>();                                
2428              ArrayList<ItemInfo> otherWorkspaceItems = new ArrayList<ItemInfo>();                                  
2429              ArrayList<LauncherAppWidgetInfo> currentAppWidgets =                                                  
2430                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2431              ArrayList<LauncherAppWidgetInfo> otherAppWidgets =                                                    
2432                      new ArrayList<LauncherAppWidgetInfo>();                                                       
2433              HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();                           
2434              HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();                             
2435                                                                                                                    
2436              filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,                   
2437                      otherWorkspaceItems);                                                                         
2438              filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,                               
2439                      otherAppWidgets);                                                                             
2440              filterCurrentFolders(currentScreenId, itemsIdMap, folders, currentFolders,                            
2441                      otherFolders);                                                                                
2442              sortWorkspaceItemsSpatially(currentWorkspaceItems);                                                   
2443              sortWorkspaceItemsSpatially(otherWorkspaceItems);                                                     
2444                                                                                                                    
2445              // Tell the workspace that we're about to start binding items                                         
2446              r = new Runnable() {                                                                                  
2447                  public void run() {                                                                               
2448                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2449                      if (callbacks != null) {                                                                      
2450                          callbacks.startBinding();                                                                 
2451                      }                                                                                             
2452                  }                                                                                                 
2453              };                                                                                                    
2454              runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                     
2455                                                                                                                    
2456              bindWorkspaceScreens(oldCallbacks, orderedScreenIds);                                                 
2457                                                                                                                    
2458              // Load items on the current page                                                                     
2459              bindWorkspaceItems(oldCallbacks, currentWorkspaceItems, currentAppWidgets,                            
2460                      currentFolders, null);                                                                        
2461              if (isLoadingSynchronously) {                                                                         
2462                  r = new Runnable() {                                                                              
2463                      public void run() {                                                                           
2464                          Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                      
2465                          if (callbacks != null && currentScreen != PagedView.INVALID_RESTORE_PAGE) {               
2466                              callbacks.onPageBoundSynchronously(currentScreen);                                    
2467                          }                                                                                         
2468                      }                                                                                             
2469                  };                                                                                                
2470                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2471              }                                                                                                     
2472                                                                                                                    
2473              // Load all the remaining pages (if we are loading synchronously, we want to defer this               
2474              // work until after the first render)                                                                 
2475              mDeferredBindRunnables.clear();                                                                       
2476              bindWorkspaceItems(oldCallbacks, otherWorkspaceItems, otherAppWidgets, otherFolders,                  
2477                      (isLoadingSynchronously ? mDeferredBindRunnables : null));                                    
2478                                                                                                                    
2479              // Tell the workspace that we're done binding items                                                   
2480              r = new Runnable() {                                                                                  
2481                  public void run() {                                                                               
2482                      Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                          
2483                      if (callbacks != null) {                                                                      
2484                          callbacks.finishBindingItems(isUpgradePath);                                              
2485                      }                                                                                             
2486                                                                                                                    
2487                      // If we're profiling, ensure this is the last thing in the queue.                            
2488                      if (DEBUG_LOADERS) {                                                                          
2489                          Log.d(TAG, "bound workspace in "                                                          
2490                              + (SystemClock.uptimeMillis()-t) + "ms");                                             
2491                      }                                                                                             
2492                                                                                                                    
2493                      mIsLoadingAndBindingWorkspace = false;                                                        
2494                  }                                                                                                 
2495              };                                                                                                    
2496              if (isLoadingSynchronously) {                                                                         
2497                  mDeferredBindRunnables.add(r);                                                                    
2498              } else {                                                                                              
2499                  runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);                                                 
2500              }                                                                                                     
2501          }                                                                                                         
2502                                                                                                                    
2503          private void loadAndBindAllApps() {                                                                       
2504              if (DEBUG_LOADERS) {                                                                                  
2505                  Log.d(TAG, "loadAndBindAllApps mAllAppsLoaded=" + mAllAppsLoaded);                                
2506              }                                                                                                     
2507              if (!mAllAppsLoaded) {                                                                                
2508                  loadAllApps();                                                                                    
2509                  synchronized (LoaderTask.this) {                                                                  
2510                      if (mStopped) {                                                                               
2511                          return;                                                                                   
2512                      }                                                                                             
2513                      mAllAppsLoaded = true;                                                                        
2514                  }                                                                                                 
2515              } else {                                                                                              
2516                  onlyBindAllApps();                                                                                
2517              }                                                                                                     
2518          }                                                                                                         
2519                                                                                                                    
2520          private void onlyBindAllApps() {                                                                          
2521              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2522              if (oldCallbacks == null) {                                                                           
2523                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2524                  Log.w(TAG, "LoaderTask running with no launcher (onlyBindAllApps)");                              
2525                  return;                                                                                           
2526              }                                                                                                     
2527                                                                                                                    
2528              // shallow copy                                                                                       
2529              @SuppressWarnings("unchecked")                                                                        
2530              final ArrayList<AppInfo> list                                                                         
2531                      = (ArrayList<AppInfo>) mBgAllAppsList.data.clone();                                           
2532              Runnable r = new Runnable() {                                                                         
2533                  public void run() {                                                                               
2534                      final long t = SystemClock.uptimeMillis();                                                    
2535                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2536                      if (callbacks != null) {                                                                      
2537                          callbacks.bindAllApplications(list);                                                      
2538                      }                                                                                             
2539                      if (DEBUG_LOADERS) {                                                                          
2540                          Log.d(TAG, "bound all " + list.size() + " apps from cache in "                            
2541                                  + (SystemClock.uptimeMillis()-t) + "ms");                                         
2542                      }                                                                                             
2543                  }                                                                                                 
2544              };                                                                                                    
2545              boolean isRunningOnMainThread = !(sWorkerThread.getThreadId() == Process.myTid());                    
2546              if (isRunningOnMainThread) {                                                                          
2547                  r.run();                                                                                          
2548              } else {                                                                                              
2549                  mHandler.post(r);                                                                                 
2550              }                                                                                                     
2551          }                                                                                                         
2552                                                                                                                    
2553          private void loadAllApps() {                                                                              
2554              final long loadTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
2555                                                                                                                    
2556              final Callbacks oldCallbacks = mCallbacks.get();                                                      
2557              if (oldCallbacks == null) {                                                                           
2558                  // This launcher has exited and nobody bothered to tell us.  Just bail.                           
2559                  Log.w(TAG, "LoaderTask running with no launcher (loadAllApps)");                                  
2560                  return;                                                                                           
2561              }                                                                                                     
2562                                                                                                                    
2563              final PackageManager packageManager = mContext.getPackageManager();                                   
2564              final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);                                       
2565              mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                     
2566                                                                                                                    
2567              // Clear the list of apps                                                                             
2568              mBgAllAppsList.clear();                                                                               
2569                                                                                                                    
2570              // Query for the set of apps                                                                          
2571              final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                  
2572              List<ResolveInfo> apps = packageManager.queryIntentActivities(mainIntent, 0);                         
2573              if (DEBUG_LOADERS) {                                                                                  
2574                  Log.d(TAG, "queryIntentActivities took "                                                          
2575                          + (SystemClock.uptimeMillis()-qiaTime) + "ms");                                           
2576                  Log.d(TAG, "queryIntentActivities got " + apps.size() + " apps");                                 
2577              }                                                                                                     
2578              // Fail if we don't have any apps                                                                     
2579              if (apps == null || apps.isEmpty()) {                                                                 
2580                  return;                                                                                           
2581              }                                                                                                     
2582              // Sort the applications by name                                                                      
2583              final long sortTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;                                 
2584              Collections.sort(apps,                                                                                
2585                      new LauncherModel.ShortcutNameComparator(packageManager, mLabelCache));                       
2586              if (DEBUG_LOADERS) {                                                                                  
2587                  Log.d(TAG, "sort took "                                                                           
2588                          + (SystemClock.uptimeMillis()-sortTime) + "ms");                                          
2589              }                                                                                                     
2590                                                                                                                    
2591              // Create the ApplicationInfos                                                                        
2592              for (int i = 0; i < apps.size(); i++) {                                                               
2593                  ResolveInfo app = apps.get(i);                                                                    
2594                  // This builds the icon bitmaps.                                                                  
2595                  mBgAllAppsList.add(new AppInfo(packageManager, app,                                               
2596                          mIconCache, mLabelCache));                                                                
2597              }                                                                                                     
2598                                                                                                                    
2599              // Huh? Shouldn't this be inside the Runnable below?                                                  
2600              final ArrayList<AppInfo> added = mBgAllAppsList.added;                                                
2601              mBgAllAppsList.added = new ArrayList<AppInfo>();                                                      
2602                                                                                                                    
2603              // Post callback on main thread                                                                       
2604              mHandler.post(new Runnable() {                                                                        
2605                  public void run() {                                                                               
2606                      final long bindTime = SystemClock.uptimeMillis();                                             
2607                      final Callbacks callbacks = tryGetCallbacks(oldCallbacks);                                    
2608                      if (callbacks != null) {                                                                      
2609                          callbacks.bindAllApplications(added);                                                     
2610                          if (DEBUG_LOADERS) {                                                                      
2611                              Log.d(TAG, "bound " + added.size() + " apps in "                                      
2612                                  + (SystemClock.uptimeMillis() - bindTime) + "ms");                                
2613                          }                                                                                         
2614                      } else {                                                                                      
2615                          Log.i(TAG, "not binding apps: no Launcher activity");                                     
2616                      }                                                                                             
2617                  }                                                                                                 
2618              });                                                                                                   
2619                                                                                                                    
2620              if (DEBUG_LOADERS) {                                                                                  
2621                  Log.d(TAG, "Icons processed in "                                                                  
2622                          + (SystemClock.uptimeMillis() - loadTime) + "ms");                                        
2623              }                                                                                                     
2624          }                                                                                                         
2625                                                                                                                    
2626          public void dumpState() {                                                                                 
2627              synchronized (sBgLock) {                                                                              
2628                  Log.d(TAG, "mLoaderTask.mContext=" + mContext);                                                   
2629                  Log.d(TAG, "mLoaderTask.mIsLaunching=" + mIsLaunching);                                           
2630                  Log.d(TAG, "mLoaderTask.mStopped=" + mStopped);                                                   
2631                  Log.d(TAG, "mLoaderTask.mLoadAndBindStepFinished=" + mLoadAndBindStepFinished);                   
2632                  Log.d(TAG, "mItems size=" + sBgWorkspaceItems.size());                                            
2633              }                                                                                                     
2634          }                                                                                                         
2635      }                                                                                                             
2636                                                                                                                    
2637      void enqueuePackageUpdated(PackageUpdatedTask task) {                                                         
2638          sWorker.post(task);                                                                                       
2639      }                                                                                                             
2640                                                                                                                    
2641      private class PackageUpdatedTask implements Runnable {                                                        
2642          int mOp;                                                                                                  
2643          String[] mPackages;                                                                                       
2644                                                                                                                    
2645          public static final int OP_NONE = 0;                                                                      
2646          public static final int OP_ADD = 1;                                                                       
2647          public static final int OP_UPDATE = 2;                                                                    
2648          public static final int OP_REMOVE = 3; // uninstlled                                                      
2649          public static final int OP_UNAVAILABLE = 4; // external media unmounted                                   
2650                                                                                                                    
2651                                                                                                                    
2652          public PackageUpdatedTask(int op, String[] packages) {                                                    
2653              mOp = op;                                                                                             
2654              mPackages = packages;                                                                                 
2655          }                                                                                                         
2656                                                                                                                    
2657          public void run() {                                                                                       
2658              final Context context = mApp.getContext();                                                            
2659                                                                                                                    
2660              final String[] packages = mPackages;                                                                  
2661              final int N = packages.length;                                                                        
2662              switch (mOp) {                                                                                        
2663                  case OP_ADD:                                                                                      
2664                      for (int i=0; i<N; i++) {                                                                     
2665                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);                  
2666                          mBgAllAppsList.addPackage(context, packages[i]);                                          
2667                      }                                                                                             
2668                      break;                                                                                        
2669                  case OP_UPDATE:                                                                                   
2670                      for (int i=0; i<N; i++) {                                                                     
2671                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]);               
2672                          mBgAllAppsList.updatePackage(context, packages[i]);                                       
2673                          WidgetPreviewLoader.removePackageFromDb(                                                  
2674                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
2675                      }                                                                                             
2676                      break;                                                                                        
2677                  case OP_REMOVE:                                                                                   
2678                  case OP_UNAVAILABLE:                                                                              
2679                      for (int i=0; i<N; i++) {                                                                     
2680                          if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]);               
2681                          mBgAllAppsList.removePackage(packages[i]);                                                
2682                          WidgetPreviewLoader.removePackageFromDb(                                                  
2683                                  mApp.getWidgetPreviewCacheDb(), packages[i]);                                     
2684                      }                                                                                             
2685                      break;                                                                                        
2686              }                                                                                                     
2687                                                                                                                    
2688              ArrayList<AppInfo> added = null;                                                                      
2689              ArrayList<AppInfo> modified = null;                                                                   
2690              final ArrayList<AppInfo> removedApps = new ArrayList<AppInfo>();                                      
2691                                                                                                                    
2692              if (mBgAllAppsList.added.size() > 0) {                                                                
2693                  added = new ArrayList<AppInfo>(mBgAllAppsList.added);                                             
2694                  mBgAllAppsList.added.clear();                                                                     
2695              }                                                                                                     
2696              if (mBgAllAppsList.modified.size() > 0) {                                                             
2697                  modified = new ArrayList<AppInfo>(mBgAllAppsList.modified);                                       
2698                  mBgAllAppsList.modified.clear();                                                                  
2699              }                                                                                                     
2700              if (mBgAllAppsList.removed.size() > 0) {                                                              
2701                  removedApps.addAll(mBgAllAppsList.removed);                                                       
2702                  mBgAllAppsList.removed.clear();                                                                   
2703              }                                                                                                     
2704                                                                                                                    
2705              final Callbacks callbacks = mCallbacks != null ? mCallbacks.get() : null;                             
2706              if (callbacks == null) {                                                                              
2707                  Log.w(TAG, "Nobody to tell about the new app.  Launcher is probably loading.");                   
2708                  return;                                                                                           
2709              }                                                                                                     
2710                                                                                                                    
2711              if (added != null) {                                                                                  
2712                  // Ensure that we add all the workspace applications to the db                                    
2713                  if (LauncherAppState.isDisableAllApps()) {                                                        




2714                      final ArrayList<ItemInfo> addedInfos = new ArrayList<ItemInfo>(added);                        
2715                      addAndBindAddedWorkspaceApps(context, addedInfos);                                            
2716                  } else {                                                                                          
2717                      addAppsToAllApps(context, added);                                                             
2718                  }                                                                                                 
2719              }                                                                                                     
2720                                                                                                                    



2721              if (modified != null) {                                                                               
2722                  final ArrayList<AppInfo> modifiedFinal = modified;                                                
2723                                                                                                                    
2724                  // Update the launcher db to reflect the changes                                                  
2725                  for (AppInfo a : modifiedFinal) {                                                                 
2726                      ArrayList<ItemInfo> infos =                                                                   
2727                              getItemInfoForComponentName(a.componentName);                                         
2728                      for (ItemInfo i : infos) {                                                                    
2729                          if (isShortcutInfoUpdateable(i)) {                                                        
2730                              ShortcutInfo info = (ShortcutInfo) i;                                                 
2731                              info.title = a.title.toString();                                                      
2732                              updateItemInDatabase(context, info);                                                  
2733                          }                                                                                         
2734                      }                                                                                             
2735                  }                                                                                                 
2736                                                                                                                    
2737                  mHandler.post(new Runnable() {                                                                    
2738                      public void run() {                                                                           
2739                          Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                              
2740                          if (callbacks == cb && cb != null) {                                                      
2741                              callbacks.bindAppsUpdated(modifiedFinal);                                             
2742                          }                                                                                         
2743                      }                                                                                             
2744                  });                                                                                               
2745              }                                                                                                     
2746                                                                                                                    
2747              final ArrayList<String> removedPackageNames =                                                         
2748                      new ArrayList<String>();                                                                      
2749              if (mOp == OP_REMOVE) {                                                                               
2750                  // Mark all packages in the broadcast to be removed                                               
2751                  removedPackageNames.addAll(Arrays.asList(packages));                                              
2752              } else if (mOp == OP_UPDATE) {                                                                        
2753                  // Mark disabled packages in the broadcast to be removed                                          
2754                  final PackageManager pm = context.getPackageManager();                                            
2755                  for (int i=0; i<N; i++) {                                                                         
2756                      if (isPackageDisabled(pm, packages[i])) {                                                     
2757                          removedPackageNames.add(packages[i]);                                                     
2758                      }                                                                                             
2759                  }                                                                                                 
2760              }                                                                                                     
2761              // Remove all the components associated with this package                                             
2762              for (String pn : removedPackageNames) {                                                               
2763                  ArrayList<ItemInfo> infos = getItemInfoForPackageName(pn);                                        
2764                  for (ItemInfo i : infos) {                                                                        
2765                      deleteItemFromDatabase(context, i);                                                           
2766                  }                                                                                                 
2767              }                                                                                                     
2768              // Remove all the specific components                                                                 
2769              for (AppInfo a : removedApps) {                                                                       
2770                  ArrayList<ItemInfo> infos = getItemInfoForComponentName(a.componentName);                         
2771                  for (ItemInfo i : infos) {                                                                        
2772                      deleteItemFromDatabase(context, i);                                                           
2773                  }                                                                                                 
2774              }                                                                                                     
2775              if (!removedPackageNames.isEmpty() || !removedApps.isEmpty()) {                                       
2776                  // Remove any queued items from the install queue                                                 
2777                  String spKey = LauncherAppState.getSharedPreferencesKey();                                        
2778                  SharedPreferences sp =                                                                            
2779                          context.getSharedPreferences(spKey, Context.MODE_PRIVATE);                                
2780                  InstallShortcutReceiver.removeFromInstallQueue(sp, removedPackageNames);                          
2781                  // Call the components-removed callback                                                           
2782                  mHandler.post(new Runnable() {                                                                    
2783                      public void run() {                                                                           
2784                          Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                              
2785                          if (callbacks == cb && cb != null) {                                                      
2786                              callbacks.bindComponentsRemoved(removedPackageNames, removedApps);                    
2787                          }                                                                                         
2788                      }                                                                                             
2789                  });                                                                                               
2790              }                                                                                                     
2791                                                                                                                    
2792              final ArrayList<Object> widgetsAndShortcuts =                                                         
2793                  getSortedWidgetsAndShortcuts(context);                                                            
2794              mHandler.post(new Runnable() {                                                                        
2795                  @Override                                                                                         
2796                  public void run() {                                                                               
2797                      Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                  
2798                      if (callbacks == cb && cb != null) {                                                          
2799                          callbacks.bindPackagesUpdated(widgetsAndShortcuts);                                       
2800                      }                                                                                             
2801                  }                                                                                                 
2802              });                                                                                                   
2803                                                                                                                    
2804              // Write all the logs to disk                                                                         
2805              mHandler.post(new Runnable() {                                                                        
2806                  public void run() {                                                                               
2807                      Callbacks cb = mCallbacks != null ? mCallbacks.get() : null;                                  
2808                      if (callbacks == cb && cb != null) {                                                          
2809                          callbacks.dumpLogsToLocalData();                                                          
2810                      }                                                                                             
2811                  }                                                                                                 
2812              });                                                                                                   
2813          }                                                                                                         
2814      }                                                                                                             
2815                                                                                                                    
2816      // Returns a list of ResolveInfos/AppWindowInfos in sorted order                                              
2817      public static ArrayList<Object> getSortedWidgetsAndShortcuts(Context context) {                               
2818          PackageManager packageManager = context.getPackageManager();                                              
2819          final ArrayList<Object> widgetsAndShortcuts = new ArrayList<Object>();                                    
2820          widgetsAndShortcuts.addAll(AppWidgetManager.getInstance(context).getInstalledProviders());                
2821          Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT);                                       
2822          widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0));                     
2823          Collections.sort(widgetsAndShortcuts,                                                                     
2824              new LauncherModel.WidgetAndShortcutNameComparator(packageManager));                                   
2825          return widgetsAndShortcuts;                                                                               
2826      }                                                                                                             
2827                                                                                                                    
2828      private static boolean isPackageDisabled(PackageManager pm, String packageName) {                             
2829          try {                                                                                                     
2830              PackageInfo pi = pm.getPackageInfo(packageName, 0);                                                   
2831              return !pi.applicationInfo.enabled;                                                                   
2832          } catch (NameNotFoundException e) {                                                                       
2833              // Fall through                                                                                       
2834          }                                                                                                         
2835          return false;                                                                                             
2836      }                                                                                                             
2837                                                                                                                    
2838      public static boolean isValidPackageComponent(PackageManager pm, ComponentName cn) {                          
2839          if (cn == null) {                                                                                         
2840              return false;                                                                                         
2841          }                                                                                                         
2842          if (isPackageDisabled(pm, cn.getPackageName())) {                                                         
2843              return false;                                                                                         
2844          }                                                                                                         
2845                                                                                                                    
2846          try {                                                                                                     
2847              // Check the activity                                                                                 
2848              PackageInfo pi = pm.getPackageInfo(cn.getPackageName(), 0);                                           
2849              return (pm.getActivityInfo(cn, 0) != null);                                                           
2850          } catch (NameNotFoundException e) {                                                                       
2851              return false;                                                                                         
2852          }                                                                                                         
2853      }                                                                                                             
2854                                                                                                                    
2855      /**                                                                                                           
2856       * Make an ShortcutInfo object for a restored application or shortcut item that points                        
2857       * to a package that is not yet installed on the system.                                                      
2858       */                                                                                                           
2859 -    public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex) {                                      
2860 +    public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) {                       
2861          final ShortcutInfo info = new ShortcutInfo();                                                             
2862          info.usingFallbackIcon = true;                                                                            
2863          info.setIcon(getFallbackIcon());                                                                          
2864          if (cursor != null) {                                                                                     
2865              info.title =  cursor.getString(titleIndex);                                                           
2866          } else {                                                                                                  
2867              info.title = "";                                                                                      
2868          }                                                                                                         
2869          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
2870 +        info.restoredIntent = intent;                                                                             
2871          return info;                                                                                              
2872      }                                                                                                             
2873                                                                                                                    
2874      /**                                                                                                           
2875       * Make an Intent object for a restored application or shortcut item that points                              
2876       * to the market page for the item.                                                                           
2877       */                                                                                                           
2878      private Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {                              
2879 +        final boolean debug = false;                                                                              
2880          ComponentName componentName = intent.getComponent();                                                      
2881          Intent marketIntent = new Intent(Intent.ACTION_VIEW);                                                     
2882          Uri marketUri = new Uri.Builder()                                                                         
2883                  .scheme("market")                                                                                 
2884                  .authority("details")                                                                             
2885                  .appendQueryParameter("id", componentName.getPackageName())                                       
2886                  .build();                                                                                         
2887 -        Log.d(TAG, "manufactured intent uri: " + marketUri.toString());                                           
2888 +        if (debug) Log.d(TAG, "manufactured intent uri: " + marketUri.toString());                                
2889          marketIntent.setData(marketUri);                                                                          
2890          return marketIntent;                                                                                      
2891      }                                                                                                             
2892                                                                                                                    
2893      /**                                                                                                           
2894       * This is called from the code that adds shortcuts from the intent receiver.  This                           
2895       * doesn't have a Cursor, but                                                                                 
2896       */                                                                                                           
2897      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context) {                 
2898          return getShortcutInfo(manager, intent, context, null, -1, -1, null);                                     
2899      }                                                                                                             
2900                                                                                                                    
2901      /**                                                                                                           
2902       * Make an ShortcutInfo object for a shortcut that is an application.                                         
2903       *                                                                                                            
2904       * If c is not null, then it will be used to fill in missing data like the title and icon.                    
2905       */                                                                                                           
2906      public ShortcutInfo getShortcutInfo(PackageManager manager, Intent intent, Context context,                   
2907              Cursor c, int iconIndex, int titleIndex, HashMap<Object, CharSequence> labelCache) {                  
2908          ComponentName componentName = intent.getComponent();                                                      
2909          final ShortcutInfo info = new ShortcutInfo();                                                             
2910          if (componentName != null && !isValidPackageComponent(manager, componentName)) {                          
2911              Log.d(TAG, "Invalid package found in getShortcutInfo: " + componentName);                             
2912              return null;                                                                                          
2913          } else {                                                                                                  
2914              try {                                                                                                 
2915                  PackageInfo pi = manager.getPackageInfo(componentName.getPackageName(), 0);                       
2916                  info.initFlagsAndFirstInstallTime(pi);                                                            
2917              } catch (NameNotFoundException e) {                                                                   
2918                  Log.d(TAG, "getPackInfo failed for package " +                                                    
2919                          componentName.getPackageName());                                                          
2920              }                                                                                                     
2921          }                                                                                                         
2922                                                                                                                    
2923          // TODO: See if the PackageManager knows about this case.  If it doesn't                                  
2924          // then return null & delete this.                                                                        
2925                                                                                                                    
2926          // the resource -- This may implicitly give us back the fallback icon,                                    
2927          // but don't worry about that.  All we're doing with usingFallbackIcon is                                 
2928          // to avoid saving lots of copies of that in the database, and most apps                                  
2929          // have icons anyway.                                                                                     
2930                                                                                                                    
2931          // Attempt to use queryIntentActivities to get the ResolveInfo (with IntentFilter info) and               
2932          // if that fails, or is ambiguious, fallback to the standard way of getting the resolve info              
2933          // via resolveActivity().                                                                                 
2934          Bitmap icon = null;                                                                                       
2935          ResolveInfo resolveInfo = null;                                                                           
2936          ComponentName oldComponent = intent.getComponent();                                                       
2937          Intent newIntent = new Intent(intent.getAction(), null);                                                  
2938          newIntent.addCategory(Intent.CATEGORY_LAUNCHER);                                                          
2939          newIntent.setPackage(oldComponent.getPackageName());                                                      
2940          List<ResolveInfo> infos = manager.queryIntentActivities(newIntent, 0);                                    
2941          for (ResolveInfo i : infos) {                                                                             
2942              ComponentName cn = new ComponentName(i.activityInfo.packageName,                                      
2943                      i.activityInfo.name);                                                                         
2944              if (cn.equals(oldComponent)) {                                                                        
2945                  resolveInfo = i;                                                                                  
2946              }                                                                                                     
2947          }                                                                                                         
2948          if (resolveInfo == null) {                                                                                
2949              resolveInfo = manager.resolveActivity(intent, 0);                                                     
2950          }                                                                                                         
2951          if (resolveInfo != null) {                                                                                
2952              icon = mIconCache.getIcon(componentName, resolveInfo, labelCache);                                    
2953          }                                                                                                         
2954          // the db                                                                                                 
2955          if (icon == null) {                                                                                       
2956              if (c != null) {                                                                                      
2957                  icon = getIconFromCursor(c, iconIndex, context);                                                  
2958              }                                                                                                     
2959          }                                                                                                         
2960          // the fallback icon                                                                                      
2961          if (icon == null) {                                                                                       
2962              icon = getFallbackIcon();                                                                             
2963              info.usingFallbackIcon = true;                                                                        
2964          }                                                                                                         
2965          info.setIcon(icon);                                                                                       
2966                                                                                                                    
2967          // from the resource                                                                                      
2968          if (resolveInfo != null) {                                                                                
2969              ComponentName key = LauncherModel.getComponentNameFromResolveInfo(resolveInfo);                       
2970              if (labelCache != null && labelCache.containsKey(key)) {                                              
2971                  info.title = labelCache.get(key);                                                                 
2972              } else {                                                                                              
2973                  info.title = resolveInfo.activityInfo.loadLabel(manager);                                         
2974                  if (labelCache != null) {                                                                         
2975                      labelCache.put(key, info.title);                                                              
2976                  }                                                                                                 
2977              }                                                                                                     
2978          }                                                                                                         
2979          // from the db                                                                                            
2980          if (info.title == null) {                                                                                 
2981              if (c != null) {                                                                                      
2982                  info.title =  c.getString(titleIndex);                                                            
2983              }                                                                                                     
2984          }                                                                                                         
2985          // fall back to the class name of the activity                                                            
2986          if (info.title == null) {                                                                                 
2987              info.title = componentName.getClassName();                                                            
2988          }                                                                                                         
2989          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;                                         
2990          return info;                                                                                              
2991      }                                                                                                             
2992                                                                                                                    
2993      static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,                                        
2994              ItemInfoFilter f) {                                                                                   
2995          HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();                                                     
2996          for (ItemInfo i : infos) {                                                                                
2997              if (i instanceof ShortcutInfo) {                                                                      
2998                  ShortcutInfo info = (ShortcutInfo) i;                                                             
2999                  ComponentName cn = info.intent.getComponent();                                                    
3000                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3001                      filtered.add(info);                                                                           
3002                  }                                                                                                 
3003              } else if (i instanceof FolderInfo) {                                                                 
3004                  FolderInfo info = (FolderInfo) i;                                                                 
3005                  for (ShortcutInfo s : info.contents) {                                                            
3006                      ComponentName cn = s.intent.getComponent();                                                   
3007                      if (cn != null && f.filterItem(info, s, cn)) {                                                
3008                          filtered.add(s);                                                                          
3009                      }                                                                                             
3010                  }                                                                                                 
3011              } else if (i instanceof LauncherAppWidgetInfo) {                                                      
3012                  LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) i;                                           
3013                  ComponentName cn = info.providerName;                                                             
3014                  if (cn != null && f.filterItem(null, info, cn)) {                                                 
3015                      filtered.add(info);                                                                           
3016                  }                                                                                                 
3017              }                                                                                                     
3018          }                                                                                                         
3019          return new ArrayList<ItemInfo>(filtered);                                                                 
3020      }                                                                                                             
3021                                                                                                                    
3022      private ArrayList<ItemInfo> getItemInfoForPackageName(final String pn) {                                      
3023          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
3024              @Override                                                                                             
3025              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
3026                  return cn.getPackageName().equals(pn);                                                            
3027              }                                                                                                     
3028          };                                                                                                        
3029          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
3030      }                                                                                                             
3031                                                                                                                    
3032      private ArrayList<ItemInfo> getItemInfoForComponentName(final ComponentName cname) {                          
3033          ItemInfoFilter filter  = new ItemInfoFilter() {                                                           
3034              @Override                                                                                             
3035              public boolean filterItem(ItemInfo parent, ItemInfo info, ComponentName cn) {                         
3036                  return cn.equals(cname);                                                                          
3037              }                                                                                                     
3038          };                                                                                                        
3039          return filterItemInfos(sBgItemsIdMap.values(), filter);                                                   
3040      }                                                                                                             
3041                                                                                                                    
3042      public static boolean isShortcutInfoUpdateable(ItemInfo i) {                                                  
3043          if (i instanceof ShortcutInfo) {                                                                          
3044              ShortcutInfo info = (ShortcutInfo) i;                                                                 
3045              // We need to check for ACTION_MAIN otherwise getComponent() might                                    
3046              // return null for some shortcuts (for instance, for shortcuts to                                     
3047              // web pages.)                                                                                        
3048              Intent intent = info.intent;                                                                          
3049              ComponentName name = intent.getComponent();                                                           
3050              if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION &&                              
3051                      Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) {                              
3052                  return true;                                                                                      
3053              }                                                                                                     
3054 +            // placeholder shortcuts get special treatment, let them through too.                                 
3055 +            if (info.getRestoredIntent() != null) {                                                               
3056 +                return true;                                                                                      
3057 +            }                                                                                                     
3058          }                                                                                                         
3059          return false;                                                                                             
3060      }                                                                                                             
3061                                                                                                                    
3062      /**                                                                                                           
3063       * Make an ShortcutInfo object for a shortcut that isn't an application.                                      
3064       */                                                                                                           
3065      private ShortcutInfo getShortcutInfo(Cursor c, Context context,                                               
3066              int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex,                        
3067              int titleIndex) {                                                                                     
3068                                                                                                                    
3069          Bitmap icon = null;                                                                                       
3070          final ShortcutInfo info = new ShortcutInfo();                                                             
3071          info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;                                            
3072                                                                                                                    
3073          // TODO: If there's an explicit component and we can't install that, delete it.                           
3074                                                                                                                    
3075          info.title = c.getString(titleIndex);                                                                     
3076                                                                                                                    
3077          int iconType = c.getInt(iconTypeIndex);                                                                   
3078          switch (iconType) {                                                                                       
3079          case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:                                                       
3080              String packageName = c.getString(iconPackageIndex);                                                   
3081              String resourceName = c.getString(iconResourceIndex);                                                 
3082              PackageManager packageManager = context.getPackageManager();                                          
3083              info.customIcon = false;                                                                              
3084              // the resource                                                                                       
3085              try {                                                                                                 
3086                  Resources resources = packageManager.getResourcesForApplication(packageName);                     
3087                  if (resources != null) {                                                                          
3088                      final int id = resources.getIdentifier(resourceName, null, null);                             
3089                      icon = Utilities.createIconBitmap(                                                            
3090                              mIconCache.getFullResIcon(resources, id), context);                                   
3091                  }                                                                                                 
3092              } catch (Exception e) {                                                                               
3093                  // drop this.  we have other places to look for icons                                             
3094              }                                                                                                     
3095              // the db                                                                                             
3096              if (icon == null) {                                                                                   
3097                  icon = getIconFromCursor(c, iconIndex, context);                                                  
3098              }                                                                                                     
3099              // the fallback icon                                                                                  
3100              if (icon == null) {                                                                                   
3101                  icon = getFallbackIcon();                                                                         
3102                  info.usingFallbackIcon = true;                                                                    
3103              }                                                                                                     
3104              break;                                                                                                
3105          case LauncherSettings.Favorites.ICON_TYPE_BITMAP:                                                         
3106              icon = getIconFromCursor(c, iconIndex, context);                                                      
3107              if (icon == null) {                                                                                   
3108                  icon = getFallbackIcon();                                                                         
3109                  info.customIcon = false;                                                                          
3110                  info.usingFallbackIcon = true;                                                                    
3111              } else {                                                                                              
3112                  info.customIcon = true;                                                                           
3113              }                                                                                                     
3114              break;                                                                                                
3115          default:                                                                                                  
3116              icon = getFallbackIcon();                                                                             
3117              info.usingFallbackIcon = true;                                                                        
3118              info.customIcon = false;                                                                              
3119              break;                                                                                                
3120          }                                                                                                         
3121          info.setIcon(icon);                                                                                       
3122          return info;                                                                                              
3123      }                                                                                                             
3124                                                                                                                    
3125      Bitmap getIconFromCursor(Cursor c, int iconIndex, Context context) {                                          
3126          @SuppressWarnings("all") // suppress dead code warning                                                    
3127          final boolean debug = false;                                                                              
3128          if (debug) {                                                                                              
3129              Log.d(TAG, "getIconFromCursor app="                                                                   
3130                      + c.getString(c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE)));                    
3131          }                                                                                                         
3132          byte[] data = c.getBlob(iconIndex);                                                                       
3133          try {                                                                                                     
3134              return Utilities.createIconBitmap(                                                                    
3135                      BitmapFactory.decodeByteArray(data, 0, data.length), context);                                
3136          } catch (Exception e) {                                                                                   
3137              return null;                                                                                          
3138          }                                                                                                         
3139      }                                                                                                             
3140                                                                                                                    
3141      ShortcutInfo addShortcut(Context context, Intent data, long container, int screen,                            
3142              int cellX, int cellY, boolean notify) {                                                               
3143          final ShortcutInfo info = infoFromShortcutIntent(context, data, null);                                    
3144          if (info == null) {                                                                                       
3145              return null;                                                                                          
3146          }                                                                                                         
3147          addItemToDatabase(context, info, container, screen, cellX, cellY, notify);                                
3148                                                                                                                    
3149          return info;                                                                                              
3150      }                                                                                                             
3151                                                                                                                    
3152      /**                                                                                                           
3153       * Attempts to find an AppWidgetProviderInfo that matches the given component.                                
3154       */                                                                                                           
3155      AppWidgetProviderInfo findAppWidgetProviderInfoWithComponent(Context context,                                 
3156              ComponentName component) {                                                                            
3157          List<AppWidgetProviderInfo> widgets =                                                                     
3158              AppWidgetManager.getInstance(context).getInstalledProviders();                                        
3159          for (AppWidgetProviderInfo info : widgets) {                                                              
3160              if (info.provider.equals(component)) {                                                                
3161                  return info;                                                                                      
3162              }                                                                                                     
3163          }                                                                                                         
3164          return null;                                                                                              
3165      }                                                                                                             
3166                                                                                                                    
3167      /**                                                                                                           
3168       * Returns a list of all the widgets that can handle configuration with a particular mimeType.                
3169       */                                                                                                           
3170      List<WidgetMimeTypeHandlerData> resolveWidgetsForMimeType(Context context, String mimeType) {                 
3171          final PackageManager packageManager = context.getPackageManager();                                        
3172          final List<WidgetMimeTypeHandlerData> supportedConfigurationActivities =                                  
3173              new ArrayList<WidgetMimeTypeHandlerData>();                                                           
3174                                                                                                                    
3175          final Intent supportsIntent =                                                                             
3176              new Intent(InstallWidgetReceiver.ACTION_SUPPORTS_CLIPDATA_MIMETYPE);                                  
3177          supportsIntent.setType(mimeType);                                                                         
3178                                                                                                                    
3179          // Create a set of widget configuration components that we can test against                               
3180          final List<AppWidgetProviderInfo> widgets =                                                               
3181              AppWidgetManager.getInstance(context).getInstalledProviders();                                        
3182          final HashMap<ComponentName, AppWidgetProviderInfo> configurationComponentToWidget =                      
3183              new HashMap<ComponentName, AppWidgetProviderInfo>();                                                  
3184          for (AppWidgetProviderInfo info : widgets) {                                                              
3185              configurationComponentToWidget.put(info.configure, info);                                             
3186          }                                                                                                         
3187                                                                                                                    
3188          // Run through each of the intents that can handle this type of clip data, and cross                      
3189          // reference them with the components that are actual configuration components                            
3190          final List<ResolveInfo> activities = packageManager.queryIntentActivities(supportsIntent,                 
3191                  PackageManager.MATCH_DEFAULT_ONLY);                                                               
3192          for (ResolveInfo info : activities) {                                                                     
3193              final ActivityInfo activityInfo = info.activityInfo;                                                  
3194              final ComponentName infoComponent = new ComponentName(activityInfo.packageName,                       
3195                      activityInfo.name);                                                                           
3196              if (configurationComponentToWidget.containsKey(infoComponent)) {                                      
3197                  supportedConfigurationActivities.add(                                                             
3198                          new InstallWidgetReceiver.WidgetMimeTypeHandlerData(info,                                 
3199                                  configurationComponentToWidget.get(infoComponent)));                              
3200              }                                                                                                     
3201          }                                                                                                         
3202          return supportedConfigurationActivities;                                                                  
3203      }                                                                                                             
3204                                                                                                                    
3205      ShortcutInfo infoFromShortcutIntent(Context context, Intent data, Bitmap fallbackIcon) {                      
3206          Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);                                    
3207          String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);                                            
3208          Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);                                  
3209                                                                                                                    
3210          if (intent == null) {                                                                                     
3211              // If the intent is null, we can't construct a valid ShortcutInfo, so we return null                  
3212              Log.e(TAG, "Can't construct ShorcutInfo with null intent");                                           
3213              return null;                                                                                          
3214          }                                                                                                         
3215                                                                                                                    
3216          Bitmap icon = null;                                                                                       
3217          boolean customIcon = false;                                                                               
3218          ShortcutIconResource iconResource = null;                                                                 
3219                                                                                                                    
3220          if (bitmap != null && bitmap instanceof Bitmap) {                                                         
3221              icon = Utilities.createIconBitmap(new FastBitmapDrawable((Bitmap)bitmap), context);                   
3222              customIcon = true;                                                                                    
3223          } else {                                                                                                  
3224              Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);                      
3225              if (extra != null && extra instanceof ShortcutIconResource) {                                         
3226                  try {                                                                                             
3227                      iconResource = (ShortcutIconResource) extra;                                                  
3228                      final PackageManager packageManager = context.getPackageManager();                            
3229                      Resources resources = packageManager.getResourcesForApplication(                              
3230                              iconResource.packageName);                                                            
3231                      final int id = resources.getIdentifier(iconResource.resourceName, null, null);                
3232                      icon = Utilities.createIconBitmap(                                                            
3233                              mIconCache.getFullResIcon(resources, id), context);                                   
3234                  } catch (Exception e) {                                                                           
3235                      Log.w(TAG, "Could not load shortcut icon: " + extra);                                         
3236                  }                                                                                                 
3237              }                                                                                                     
3238          }                                                                                                         
3239                                                                                                                    
3240          final ShortcutInfo info = new ShortcutInfo();                                                             
3241                                                                                                                    
3242          if (icon == null) {                                                                                       
3243              if (fallbackIcon != null) {                                                                           
3244                  icon = fallbackIcon;                                                                              
3245              } else {                                                                                              
3246                  icon = getFallbackIcon();                                                                         
3247                  info.usingFallbackIcon = true;                                                                    
3248              }                                                                                                     
3249          }                                                                                                         
3250          info.setIcon(icon);                                                                                       
3251                                                                                                                    
3252          info.title = name;                                                                                        
3253          info.intent = intent;                                                                                     
3254          info.customIcon = customIcon;                                                                             
3255          info.iconResource = iconResource;                                                                         
3256                                                                                                                    
3257          return info;                                                                                              
3258      }                                                                                                             
3259                                                                                                                    
3260      boolean queueIconToBeChecked(HashMap<Object, byte[]> cache, ShortcutInfo info, Cursor c,                      
3261              int iconIndex) {                                                                                      
3262          // If apps can't be on SD, don't even bother.                                                             
3263          if (!mAppsCanBeOnRemoveableStorage) {                                                                     
3264              return false;                                                                                         
3265          }                                                                                                         
3266          // If this icon doesn't have a custom icon, check to see                                                  
3267          // what's stored in the DB, and if it doesn't match what                                                  
3268          // we're going to show, store what we are going to show back                                              
3269          // into the DB.  We do this so when we're loading, if the                                                 
3270          // package manager can't find an icon (for example because                                                
3271          // the app is on SD) then we can use that instead.                                                        
3272          if (!info.customIcon && !info.usingFallbackIcon) {                                                        
3273              cache.put(info, c.getBlob(iconIndex));                                                                
3274              return true;                                                                                          
3275          }                                                                                                         
3276          return false;                                                                                             
3277      }                                                                                                             
3278      void updateSavedIcon(Context context, ShortcutInfo info, byte[] data) {                                       
3279          boolean needSave = false;                                                                                 
3280          try {                                                                                                     
3281              if (data != null) {                                                                                   
3282                  Bitmap saved = BitmapFactory.decodeByteArray(data, 0, data.length);                               
3283                  Bitmap loaded = info.getIcon(mIconCache);                                                         
3284                  needSave = !saved.sameAs(loaded);                                                                 
3285              } else {                                                                                              
3286                  needSave = true;                                                                                  
3287              }                                                                                                     
3288          } catch (Exception e) {                                                                                   
3289              needSave = true;                                                                                      
3290          }                                                                                                         
3291          if (needSave) {                                                                                           
3292              Log.d(TAG, "going to save icon bitmap for info=" + info);                                             
3293              // This is slower than is ideal, but this only happens once                                           
3294              // or when the app is updated with a new icon.                                                        
3295              updateItemInDatabase(context, info);                                                                  
3296          }                                                                                                         
3297      }                                                                                                             
3298                                                                                                                    
3299      /**                                                                                                           
3300       * Return an existing FolderInfo object if we have encountered this ID previously,                            
3301       * or make a new one.                                                                                         
3302       */                                                                                                           
3303      private static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {                      
3304          // See if a placeholder was created for us already                                                        
3305          FolderInfo folderInfo = folders.get(id);                                                                  
3306          if (folderInfo == null) {                                                                                 
3307              // No placeholder -- create a new instance                                                            
3308              folderInfo = new FolderInfo();                                                                        
3309              folders.put(id, folderInfo);                                                                          
3310          }                                                                                                         
3311          return folderInfo;                                                                                        
3312      }                                                                                                             
3313                                                                                                                    
3314      public static final Comparator<AppInfo> getAppNameComparator() {                                              
3315          final Collator collator = Collator.getInstance();                                                         
3316          return new Comparator<AppInfo>() {                                                                        
3317              public final int compare(AppInfo a, AppInfo b) {                                                      
3318                  int result = collator.compare(a.title.toString().trim(),                                          
3319                          b.title.toString().trim());                                                               
3320                  if (result == 0) {                                                                                
3321                      result = a.componentName.compareTo(b.componentName);                                          
3322                  }                                                                                                 
3323                  return result;                                                                                    
3324              }                                                                                                     
3325          };                                                                                                        
3326      }                                                                                                             
3327      public static final Comparator<AppInfo> APP_INSTALL_TIME_COMPARATOR                                           
3328              = new Comparator<AppInfo>() {                                                                         
3329          public final int compare(AppInfo a, AppInfo b) {                                                          
3330              if (a.firstInstallTime < b.firstInstallTime) return 1;                                                
3331              if (a.firstInstallTime > b.firstInstallTime) return -1;                                               
3332              return 0;                                                                                             
3333          }                                                                                                         
3334      };                                                                                                            
3335      public static final Comparator<AppWidgetProviderInfo> getWidgetNameComparator() {                             
3336          final Collator collator = Collator.getInstance();                                                         
3337          return new Comparator<AppWidgetProviderInfo>() {                                                          
3338              public final int compare(AppWidgetProviderInfo a, AppWidgetProviderInfo b) {                          
3339                  return collator.compare(a.label.toString().trim(), b.label.toString().trim());                    
3340              }                                                                                                     
3341          };                                                                                                        
3342      }                                                                                                             
3343      static ComponentName getComponentNameFromResolveInfo(ResolveInfo info) {                                      
3344          if (info.activityInfo != null) {                                                                          
3345              return new ComponentName(info.activityInfo.packageName, info.activityInfo.name);                      
3346          } else {                                                                                                  
3347              return new ComponentName(info.serviceInfo.packageName, info.serviceInfo.name);                        
3348          }                                                                                                         
3349      }                                                                                                             
3350      public static class ShortcutNameComparator implements Comparator<ResolveInfo> {                               
3351          private Collator mCollator;                                                                               
3352          private PackageManager mPackageManager;                                                                   
3353          private HashMap<Object, CharSequence> mLabelCache;                                                        
3354          ShortcutNameComparator(PackageManager pm) {                                                               
3355              mPackageManager = pm;                                                                                 
3356              mLabelCache = new HashMap<Object, CharSequence>();                                                    
3357              mCollator = Collator.getInstance();                                                                   
3358          }                                                                                                         
3359          ShortcutNameComparator(PackageManager pm, HashMap<Object, CharSequence> labelCache) {                     
3360              mPackageManager = pm;                                                                                 
3361              mLabelCache = labelCache;                                                                             
3362              mCollator = Collator.getInstance();                                                                   
3363          }                                                                                                         
3364          public final int compare(ResolveInfo a, ResolveInfo b) {                                                  
3365              CharSequence labelA, labelB;                                                                          
3366              ComponentName keyA = LauncherModel.getComponentNameFromResolveInfo(a);                                
3367              ComponentName keyB = LauncherModel.getComponentNameFromResolveInfo(b);                                
3368              if (mLabelCache.containsKey(keyA)) {                                                                  
3369                  labelA = mLabelCache.get(keyA);                                                                   
3370              } else {                                                                                              
3371                  labelA = a.loadLabel(mPackageManager).toString().trim();                                          
3372                                                                                                                    
3373                  mLabelCache.put(keyA, labelA);                                                                    
3374              }                                                                                                     
3375              if (mLabelCache.containsKey(keyB)) {                                                                  
3376                  labelB = mLabelCache.get(keyB);                                                                   
3377              } else {                                                                                              
3378                  labelB = b.loadLabel(mPackageManager).toString().trim();                                          
3379                                                                                                                    
3380                  mLabelCache.put(keyB, labelB);                                                                    
3381              }                                                                                                     
3382              return mCollator.compare(labelA, labelB);                                                             
3383          }                                                                                                         
3384      };                                                                                                            
3385      public static class WidgetAndShortcutNameComparator implements Comparator<Object> {                           
3386          private Collator mCollator;                                                                               
3387          private PackageManager mPackageManager;                                                                   
3388          private HashMap<Object, String> mLabelCache;                                                              
3389          WidgetAndShortcutNameComparator(PackageManager pm) {                                                      
3390              mPackageManager = pm;                                                                                 
3391              mLabelCache = new HashMap<Object, String>();                                                          
3392              mCollator = Collator.getInstance();                                                                   
3393          }                                                                                                         
3394          public final int compare(Object a, Object b) {                                                            
3395              String labelA, labelB;                                                                                
3396              if (mLabelCache.containsKey(a)) {                                                                     
3397                  labelA = mLabelCache.get(a);                                                                      
3398              } else {                                                                                              
3399                  labelA = (a instanceof AppWidgetProviderInfo) ?                                                   
3400                      ((AppWidgetProviderInfo) a).label :                                                           
3401                      ((ResolveInfo) a).loadLabel(mPackageManager).toString().trim();                               
3402                  mLabelCache.put(a, labelA);                                                                       
3403              }                                                                                                     
3404              if (mLabelCache.containsKey(b)) {                                                                     
3405                  labelB = mLabelCache.get(b);                                                                      
3406              } else {                                                                                              
3407                  labelB = (b instanceof AppWidgetProviderInfo) ?                                                   
3408                      ((AppWidgetProviderInfo) b).label :                                                           
3409                      ((ResolveInfo) b).loadLabel(mPackageManager).toString().trim();                               
3410                  mLabelCache.put(b, labelB);                                                                       
3411              }                                                                                                     
3412              return mCollator.compare(labelA, labelB);                                                             
3413          }                                                                                                         
3414      };                                                                                                            
3415                                                                                                                    
3416      public void dumpState() {                                                                                     
3417          Log.d(TAG, "mCallbacks=" + mCallbacks);                                                                   
3418          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.data", mBgAllAppsList.data);                           
3419          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.added", mBgAllAppsList.added);                         
3420          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.removed", mBgAllAppsList.removed);                     
3421          AppInfo.dumpApplicationInfoList(TAG, "mAllAppsList.modified", mBgAllAppsList.modified);                   
3422          if (mLoaderTask != null) {                                                                                
3423              mLoaderTask.dumpState();                                                                              
3424          } else {                                                                                                  
3425              Log.d(TAG, "mLoaderTask=null");                                                                       
3426          }                                                                                                         
3427      }                                                                                                             
3428  }